/*---------------------------------------------------------------

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Copyright (c) Microsoft Corporation.  All rights reserved.

SafeInt.hpp

This header implements an integer handling class designed to catch
unsafe integer operations

This header compiles properly at warning level 4.

Please read the leading comments before using the class.

Version 2.0
---------------------------------------------------------------*/
#ifndef SAFEINT_HPP
#define SAFEINT_HPP

#include <assert.h>

#ifndef C_ASSERT
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
#endif

/*
*  The SafeInt class is designed to have as low an overhead as possible
*  while still ensuring that all integer operations are conducted safely.
*  Nearly every operator has been overloaded, with a very few exceptions.
*
*  A usability-safety trade-off has been made to help ensure safety. This 
*  requires that every operation return either a SafeInt or a bool. If we 
*  allowed an operator to return a base integer type T, then the following 
*  can happen:
*  
*  char i = SafeInt<char>(32) * 2 + SafeInt<char>(16) * 4;
*
*  The * operators take precedence, get overloaded, return a char, and then 
*  you have:
*
*  char i = (char)64 + (char)64; //overflow!
*  
*  This situation would mean that safety would depend on usage, which isn't
*  acceptable. The problem that this leaves us with is that you'd like to be able 
*  to do something like:
*
*  void* ptr = malloc(SafeInt<unsigned short>(23) * SafeInt<unsigned short>(HowMany));
*
*  and have it be a safe operation. The way out of this is to use the following type of
*  construct:
*
*  int m = (int)(s | s1);
*  or even:
*  int m = s | s1;
*
*  One key operator that is missing is an implicit cast to type T. The reason for
*  this is that if there is an implicit cast operator, then we end up with
*  an ambiguous compile-time precedence. Because of this amiguity, there
*  are two methods that are provided:
*
*  SafeInt::Value() - returns the value of the object as an integer
*
*  Update - the Value method is deprecated. The correct way to get the value 
*  is by using the casting operator.
*
*  SafeInt::Ptr()   - returns the address of the internal integer
*  Note - the '&' (address of) operator has been overloaded and returns
*         the address of the internal integer.
*
*  Update - casting operators for the 8 integer types are now provided
*
*  The SafeInt class should be used in any circumstances where ensuring
*  integrity of the calculations is more important than performance. See Performance
*  Notes below for additional information. 
*
*  Many of the conditionals will optimize out or be inlined for a release
*  build (especially with /Ox), but it does have significantly more overhead, 
*  especially for signed numbers. If you do not _require_ negative numbers, use 
*  unsigned integer types - certain types of problems cannot occur, and this class
*  performs most efficiently.
*
*  Here's an example of when the class should ideally be used -
*
*  void* AllocateMemForStructs(int StructSize, int HowMany)
*  {
*     SafeInt<unsigned long> s(StructSize);
*
*     s *= HowMany;
*
*     return malloc(s);
*
*  }
*
*  Here's when it should NOT be used:
*
*  void foo()
*  {
*    int i;
*
*    for(i = 0; i < 0xffff; i++)
*      ....
*  }
*
*  Error handling - a SafeInt class will throw exceptions if something
*  objectionable happens. The exceptions are SafeIntException classes,
*  which contain an enum as a code.
*
*  Typical usage might be:
*
*  bool foo()
*  {
*    SafeInt<unsigned long> s; //note that s == 0 unless set
*
*    try{
*      s *= 23;
*      ....
*    }
*    catch(SafeIntException err)
*    {
*       //handle errors here
*    }
*  }
*
*  Performance:
*
*  Due to the highly nested nature of this class, you can expect relatively poor
*  performance in unoptimized code. In tests of optimized code vs. correct inline checks
*  in native code, this class has been found to take approximately 8% more CPU time (this varies),
*  most of which is due to exception handling. Solutions:
*
*  1) Compile optimized code - /Ox is best, /O2 also performs well. Interestingly, /O1
*     (optimize for size) does not work as well. 
*  2) If that 8% hit is really a serious problem, walk through the code and inline the
*     exact same checks as the class uses.
*  3) Some operations are more difficult than others - avoid using signed integers, and if
*     possible keep them all the same size. 64-bit integers are also expensive. Mixing 
*     different integer sizes and types may prove expensive. Be aware that literals are
*     actually ints. For best performance, cast literals to the type desired.
*
*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*                                          IMPORTANT
*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*  4) The Microsoft C++ compiler cannot inline when both C++ exceptions are used (the default for
*     this class) AND the return is by value. The overhead of function calls can be significant.
*
*     !!!!!!!!!!!!!!!!!!!!!!!!!!!!! Update! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*     As it turns out, this is only the case when the object has a destructor. It doesn't matter if
*     the destructor DOES anything, it just has to  be there. So ~ClassName(){}; will cause lots of 
*     method calls not to inline. The destructor has thus been removed from this class.
*
*     Some of the comments immediately below are out of date, but do still apply in some cases. The
*     warning about overriding the default handler with ANYTHING other than some exception handling
*     mechanism remains important.
*
*     If you're using this version, and notice calls in your assembly, option 2 below may provide a
*     way around the issue.
*
*     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
*     There are two ways to work around the problem:
*       1) Override the default error handler to use something else. Do so carefully! This will work
*          well in trivial cases, but can result in errors if you continue after a problem. The result
*          of a calculation after the handler is called is UNDEFINED!!!
*          
*          One suggested override would be to log the problem and exit the application
*
*       2) Be tricky. For example:
*
*          SafeInt<int> result, a(i), b(j);
*          result = a + b;
*
*          Creates a call to operator+ and operator=. But if you can do it like this:
*          SafeInt<int> a(i);
*          a += b;
*          
*          Then it inlines nicely because the result of += is passed by reference, and you will get very 
*          close to the same performance as doing it in C.
*
*  Binary Operators
*  
*  All of the binary operators have certain assumptions built into the class design. 
*  This is to ensure correctness. Notes on each class of operator follow:
*  
*  Arithmetic Operators (*,/,+,-,%)
*  There are three possible variants:
*  SafeInt<T> op SafeInt<T>
*  SafeInt<T> op U
*  U op SafeInt<T>
*  
*  The SafeInt<T> op SafeInt<U> variant is explicitly not supported, and if you try to do 
*  this the compiler with throw the following error:
*  
*  error C2593: 'operator *' is ambiguous
*  
*  This is because the arithmetic operators are required to return a SafeInt of some type. 
*  The compiler cannot know whether you'd prefer to get a type T or a type U returned. If 
*  you need to do this, you need to extract the value contained within one of the two using 
*  the casting operator. For example:
*  
*  SafeInt<T> t, result;
*  SafeInt<U> u;
*  
*  result = t * (U)u;
*  
*  UPDATE: I am considering ways of working around this problem.
*
*  Comparison Operators
*  Because each of these operators return type bool, mixing SafeInts of differing types is 
*  allowed.
*  
*  Shift Operators
*  Shift operators always return the type on the left hand side of the operator. Mixed type 
*  operations are allowed because the return type is always known.
*  
*  Boolean Operators
*  Like comparison operators, these overloads always return type bool, and mixed-type SafeInts 
*  are allowed. Additionally, specific overloads exist for type bool on both sides of the 
*  operator.
*  
*  Binary Operators
*  Mixed-type operations are discouraged, however some provision has been made in order to 
*  enable things like:
*  
*  SafeInt<char> c = 2;
*  
*  if(c & 0x02)
*    ...
*  
*  The "0x02" is actually an int, and it needs to work. The rule is that if the non-SafeInt type 
*  can be cast to the type of the SafeInt, and back to the original type without losing any 
*  significant bits then the operation is allowed.
*  
*  
*  Documented issues:
*
*  This header compiles correctly at /W4 using VC++ 7.1 (Version 13.10.3077). 
*  It is strongly recommended that any code doing integer manipulation be compiled at /W4 
*  - there are a number of warnings which pertain to integer manipulation enabled that are 
*  not enabled at /W3 (default for VC++)
*
*  Perf note - postfix operators are slightly more costly than prefix operators.
*  Unless you're actually assigning it to something, ++SafeInt is less expensive than SafeInt++
*
*  The comparison operator behavior in this class varies from the ANSI definition, which is 
*  arguably broken. As an example, consider the following:
*  
*  unsigned int l = 0xffffffff;
*  char c = -1;
*  
*  if(c == l)
*    printf("Why is -1 equal to 4 billion???\n");
*  
*  The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets 
*  cast again to an unsigned int, losing the true value. This behavior is despite the fact that
*  an _int64 exists, and the following code will yield a different (and intuitively correct)
*  answer:
*  
*  if((_int64)c == (_int64)l))
*    printf("Why is -1 equal to 4 billion???\n");
*  else
*    printf("Why doesn't the compiler upcast to 64-bits when needed?\n");
*  
*  Note that combinations with smaller integers won't display the problem - if you 
*  changed "unsigned int" above to "unsigned short", you'd get the right answer.
*
*  If you prefer to retain the ANSI standard behavior insert 
*  #define ANSI_CONVERSIONS 
*  into your source. Behavior differences occur in the following cases:
*  8, 16, and 32-bit signed int, unsigned 32-bit int
*  any signed int, unsigned 64-bit int
*  Note - the signed int must be negative to show the problem
*  
*  
*  Revision history:
*
*  Oct 12, 2003 - Created
*  Author - David LeBlanc - dleblanc@microsoft.com
*
*  Oct 27, 2003 - fixed numerous items pointed out by michmarc and bdawson
*  Dec 28, 2003 - 1.0
*                 added support for mixed-type operations
*                 thanks to vikramh
*                 also fixed broken _int64 multiplication section
*                 added extended support for mixed-type operations where possible
*  Jan 28, 2004 - 1.0.1
*                 changed WCHAR to wchar_t
*                 fixed a construct in two mixed-type assignment overloads that was 
*                 not compiling on some compilers
*                 Also changed name of private method to comply with standards on 
*                 reserved names
*                 Thanks to Niels Dekker for the input
*  Feb 12, 2004 - 1.0.2
*                 Minor changes to remove dependency on Windows headers
*                 Consistently used _int16, _int32 and _int64 to ensure
*                 portability
*  May 10, 2004 - 1.0.3
*                 Corrected bug in one case of GreaterThan
*  July 22, 2004 - 1.0.4
*                 Tightened logic in addition check (saving 2 instructions)
*                 Pulled error handler out into function to enable user-defined replacement
*                 Made internal type of SafeIntException an enum (as per Niels' suggestion)
*                 Added casts for base integer types (as per Scott Meyers' suggestion)
*                 Updated usage information - see important new perf notes.
*                 Cleaned up several const issues (more thanks to Niels)
*
*  Oct 1, 2004 - 1.0.5
*                 Added support for SEH exceptions instead of C++ exceptions - Win32 only
*                 Made handlers for DIV0 and overflows individually overridable
*                 Commented out the destructor - major perf gains here
*                 Added cast operator for type long, since long != _int32
*				  Corrected a couple of missing const modifiers
*                 Fixed broken >= and <= operators for type U op SafeInt<T>
*  Nov 5, 2004 - 1.0.6
*                 Implemented new logic in binary operators to resolve issues with
*                 implicit casts
*                 Fixed casting operator because char != signed char
*                 Defined _int32 as int instead of long
*                 Removed unsafe SafeInt::Value method
*                 Re-implemented casting operator as a result of removing Value method
*  Dec 1, 2004 - 1.0.7
*                 Implemented specialized operators for pointer arithmetic
*                 Created overloads for cases of U op= SafeInt. What you do with U 
*                 after that may be dangerous.
*                 Fixed bug in corner case of MixedSizeModulus
*                 Fixed bug in MixedSizeMultiply and MixedSizeDivision with input of 0
*                 Added throw() decorations
*
*  Apr 12, 2005   Extensive revisions to leverage template specialization.
*                 
*/

#pragma warning(push)
//this avoids warnings from the unary '-' operator being applied to unsigned numbers
//the overload itself resolves to nothing for the unsigned case
#pragma warning(disable:4146)
// conditional expression is constant - these are used intentionally
#pragma warning(disable:4127)
//cast truncates constant value
#pragma warning(disable:4310)



//use these if the compiler does not support _intXX
#ifdef NEEDS_INT_DEFINED
#define _int16 short
#define _int32 int
#define _int64 long long
#endif

/* catch these to handle errors
** Currently implemented code values:
** ERROR_ARITHMETIC_OVERFLOW
** EXCEPTION_INT_DIVIDE_BY_ZERO
*/

enum SafeIntError
{
	SafeIntNoError = 0,
	SafeIntArithmeticOverflow,
	SafeIntDivideByZero
};

//error handler prototypes
//if you want a custom handler:
//set #define SAFEINT_CUSTOM_OVERFLOW_HANDLER
//or #define SAFEINT_CUSTOM_DIVZERO_HANDLER
//and implement these functions

//OR set #define SAFEINT_RAISE_EXCEPTION and use RaiseException (Win32 only)

__declspec(noreturn) void __stdcall SafeIntOnOverflow();
__declspec(noreturn) void __stdcall SafeIntOnDivZero();

#ifndef SAFEINT_RAISE_EXCEPTION
class SafeIntException
{
public:
	SafeIntException(){m_code = SafeIntNoError;}
	SafeIntException(SafeIntError code)
	{
		m_code = code;
	}
	SafeIntError m_code;
};

#ifndef SAFEINT_CUSTOM_OVERFLOW_HANDLER
__declspec(noreturn) inline void __stdcall SafeIntOnOverflow()
{
	throw SafeIntException(SafeIntArithmeticOverflow);
}
#endif

#ifndef SAFEINT_CUSTOM_DIVZERO_HANDLER
__declspec(noreturn) inline void __stdcall SafeIntOnDivZero()
{
	throw SafeIntException(SafeIntDivideByZero);
}
#endif

#else //SAFEINT_RAISE_EXCEPTION

__declspec(noreturn) inline void __stdcall SafeIntOnOverflow()
{
	RaiseException(EXCEPTION_INT_OVERFLOW, EXCEPTION_NONCONTINUABLE, 0, 0);
}

__declspec(noreturn) inline void __stdcall SafeIntOnDivZero()
{
	RaiseException(EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_NONCONTINUABLE, 0, 0);
}
#endif

template<typename T> class IntTraits
{
public:
	enum
	{
		isSigned  = ((T)(-1) < 0),
		is64Bit   = (sizeof(T) == 8),
		is32Bit   = (sizeof(T) == 4),
		is16Bit   = (sizeof(T) == 2),
		is8Bit    = (sizeof(T) == 1),
		isLT32Bit = (sizeof(T) < 4),
		isLT64Bit = (sizeof(T) < 8),
		isInt8    = (sizeof(T) == 1 && isSigned),
		isUint8   = (sizeof(T) == 1 && !isSigned),
		isInt16   = (sizeof(T) == 2 && isSigned),
		isUint16  = (sizeof(T) == 2 && !isSigned),
		isInt32   = (sizeof(T) == 4 && isSigned),
		isUint32  = (sizeof(T) == 4 && !isSigned),
		isInt64   = (sizeof(T) == 8 && isSigned),
		isUint64  = (sizeof(T) == 8 && !isSigned),
		bitCount  = (sizeof(T)*8)
	};

	// On version 13.10 enums cannot define __int64 values
	// so we'll use const statics instead!
	const static T maxInt = isSigned ? ((T)~((T)1 << (T)(bitCount-1))) : ((T)(~(T)0));
	const static T minInt = isSigned ? ((T)((T)1 << (T)(bitCount-1)))  : ((T)0);
};

template <typename T, typename U> class IntCompare
{
public:
	enum
	{
		isBothSigned = (IntTraits<T>::isSigned && IntTraits<U>::isSigned),
		isBothUnsigned = (!IntTraits<T>::isSigned && !IntTraits<U>::isSigned),
		isLikeSigned = (IntTraits<T>::isSigned == IntTraits<U>::isSigned),
		isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) ||
		            (IntTraits<T>::isSigned && sizeof(T) > sizeof(U))),
		isBothLT32Bit = (IntTraits<T>::isLT32Bit && IntTraits<U>::isLT32Bit),
		isBothLT64Bit = (IntTraits<T>::isLT64Bit && IntTraits<U>::isLT64Bit),
	};
};

//all of the arithmetic operators can be solved by the same code within
//each of these regions without resorting to compile-time constant conditionals
//most operators collapse the problem into less than the 20 zones, but this is used
//as the first cut
//using this also helps ensure that we handle all of the possible cases correctly

template <typename T, typename U> class IntRegion
{
public:
	enum
	{
		//unsigned-unsigned zone
		IntZone_UintLT32_UintLT32 = IntCompare<T,U>::isBothUnsigned && IntCompare<T,U>::isBothLT32Bit,
		IntZone_Uint32_UintLT64   = IntCompare<T,U>::isBothUnsigned && IntTraits<T>::is32Bit && IntTraits<U>::isLT64Bit,
		IntZone_UintLT32_Uint32   = IntCompare<T,U>::isBothUnsigned && IntTraits<T>::isLT32Bit && IntTraits<U>::is32Bit,
		IntZone_Uint64_Uint       = IntCompare<T,U>::isBothUnsigned && IntTraits<T>::is64Bit,
		IntZone_UintLT64_Uint64    = IntCompare<T,U>::isBothUnsigned && IntTraits<T>::isLT64Bit && IntTraits<U>::is64Bit,
 	    //unsigned-signed
	    IntZone_UintLT32_IntLT32  = !IntTraits<T>::isSigned && IntTraits<U>::isSigned && IntCompare<T,U>::isBothLT32Bit,
		IntZone_Uint32_IntLT64    = IntTraits<T>::isUint32 && IntTraits<U>::isSigned && IntTraits<U>::isLT64Bit,
		IntZone_UintLT32_Int32    = !IntTraits<T>::isSigned && IntTraits<T>::isLT32Bit && IntTraits<U>::isInt32,
		IntZone_Uint64_Int        = IntTraits<T>::isUint64 && IntTraits<U>::isSigned,
		IntZone_UintLT64_Int64    = !IntTraits<T>::isSigned && IntTraits<T>::isLT64Bit && IntTraits<U>::isInt64,
	    //signed-signed
		IntZone_IntLT32_IntLT32   = IntCompare<T,U>::isBothSigned && IntCompare<T,U>::isBothLT32Bit,
		IntZone_Int32_IntLT64     = IntCompare<T,U>::isBothSigned && IntTraits<T>::is32Bit && IntTraits<U>::isLT64Bit,
		IntZone_IntLT32_Int32     = IntCompare<T,U>::isBothSigned && IntTraits<T>::isLT32Bit && IntTraits<U>::is32Bit,
		IntZone_Int64_Int         = IntCompare<T,U>::isBothSigned && IntTraits<T>::is64Bit,
		IntZone_IntLT64_Int64     = IntCompare<T,U>::isBothSigned && IntTraits<T>::isLT64Bit && IntTraits<U>::is64Bit,
        //signed-unsigned
		IntZone_IntLT32_UintLT32  = IntTraits<T>::isSigned && !IntTraits<U>::isSigned && IntCompare<T,U>::isBothLT32Bit,
		IntZone_Int32_UintLT32    = IntTraits<T>::isInt32 && !IntTraits<U>::isSigned && IntTraits<U>::isLT32Bit,
		IntZone_IntLT64_Uint32    = IntTraits<T>::isSigned && IntTraits<T>::isLT64Bit && IntTraits<U>::isUint32,
		IntZone_Int64_UintLT64    = IntTraits<T>::isInt64 && !IntTraits<U>::isSigned && IntTraits<U>::isLT64Bit,
		IntZone_Int_Uint64        = IntTraits<T>::isSigned && IntTraits<U>::isUint64
	};
};

//useful function to help with getting the magnitude of a negative number
enum AbsMethod
{
	AbsMethodInt,
	AbsMethodInt64,
	AbsMethodError
};

template <typename T>
class GetAbsMethod
{
public:
	enum
	{
		method = IntTraits<T>::isLT64Bit && IntTraits<T>::isSigned ? AbsMethodInt :
	             IntTraits<T>::isInt64 ? AbsMethodInt64 : AbsMethodError
	};
};

template <typename T, int> class AbsValueHelper;

template <typename T> class AbsValueHelper <T, AbsMethodInt>
{
public:
	static unsigned _int32 Abs(T t)
	{
		assert(t < 0);
		return (unsigned _int32)-t;
	}
};

template <typename T> class AbsValueHelper <T, AbsMethodInt64>
{
public:
	static unsigned _int64 Abs(T t)
	{
		assert(t < 0);
		return (unsigned _int64)-t;
	}
};

//core logic to determine casting behavior
enum CastMethod
{
	CastOK = 0,
	CastCheckLTZero,
	CastCheckGTMax,
	CastCheckMinMaxUnsigned,
	CastCheckMinMaxSigned
};

template <typename T, typename U>
class GetCastMethod
{
public:
	enum
	{
		method = IntCompare<T, U>::isCastOK ? CastOK :
	               ((IntTraits<T>::isSigned && !IntTraits<U>::isSigned && sizeof(U) >= sizeof(T)) ||
				    (IntCompare<T, U>::isBothUnsigned && sizeof(U) > sizeof(T))) ? CastCheckGTMax :
				   (!IntTraits<T>::isSigned && IntTraits<U>::isSigned && sizeof(T) >= sizeof(U)) ? CastCheckLTZero :
				   (!IntTraits<T>::isSigned) ? CastCheckMinMaxUnsigned : CastCheckMinMaxSigned
	};
};

template <typename T, typename U, int> class SafeCastHelper;

template <typename T, typename U> class SafeCastHelper <T, U, CastOK>
{
public:
	static T Cast(U u){return (T)u;}
};

template <typename T, typename U> class SafeCastHelper <T, U, CastCheckLTZero>
{
public:
	static T Cast(U u)
	{
		if(u < 0)
			SafeIntOnOverflow();

		return (T)u;
	}
};

template <typename T, typename U> class SafeCastHelper <T, U, CastCheckGTMax>
{
public:
	static T Cast(U u)
	{
		if(u > IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)u;
	}
};

template <typename T, typename U> class SafeCastHelper <T, U, CastCheckMinMaxUnsigned>
{
public:
	static T Cast(U u)
	{
		//U is signed - T could be either signed or unsigned
		if(u > IntTraits<T>::maxInt || u < 0)
			SafeIntOnOverflow();

		return (T)u;
	}
};

template <typename T, typename U> class SafeCastHelper <T, U, CastCheckMinMaxSigned>
{
public:
	static T Cast(U u)
	{
		//T, U are signed
		if(u > IntTraits<T>::maxInt || u < IntTraits<T>::minInt)
			SafeIntOnOverflow();

		return (T)u;
	}
};

//core logic to determine whether a comparison is valid, or needs special treatment
enum ComparisonMethod
{
	ComparisonMethod_Ok = 0,
	ComparisonMethod_CastInt,
	ComparisonMethod_CastInt64,
	ComparisonMethod_UnsignedT,
	ComparisonMethod_UnsignedU
};

	//Note - the standard is arguably broken in the case of some integer
	//conversion operations
	//For example, signed char a = -1 = 0xff
	//             unsigned int b = 0xffffffff
	//if you then test if a < b, a value-preserving cast
	//is made, and you're essentially testing
	// (unsigned int)a < b == false
	//
	// I do not think this makes sense - if you perform
	// a cast to an _int64, which can clearly preserve both value and signedness
	// then you get a different and intuitively correct answer
	// IMHO, -1 should be less than 4 billion
	// If you prefer to retain the ANSI standard behavior
	// insert #define ANSI_CONVERSIONS into your source
	// Behavior differences occur in the following cases:
	// 8, 16, and 32-bit signed int, unsigned 32-bit int
	// any signed int, unsigned 64-bit int
	// Note - the signed int must be negative to show the problem

template <typename T, typename U>
class ValidComparison
{
public:
	enum
	{
#ifdef ANSI_CONVERSIONS
		method = ComparisonMethod_Ok
#else
		method = ((IntCompare<T, U>::isLikeSigned) ? ComparisonMethod_Ok :
		          ((IntTraits<T>::isSigned && sizeof(T) < 8 && sizeof(U) < 4) ||
				 (IntTraits<U>::isSigned && sizeof(T) < 4 && sizeof(U) < 8)) ? ComparisonMethod_CastInt :
				 ((IntTraits<T>::isInt64 && sizeof(U) < 8) ||
				  (IntTraits<U>::isInt64 && sizeof(T) < 8)) ? ComparisonMethod_CastInt64 :
				 (!IntTraits<T>::isSigned) ? ComparisonMethod_UnsignedT : ComparisonMethod_UnsignedU)
#endif
	};
};

template <typename T, typename U, int state> class EqualityTest;

template <typename T, typename U> class EqualityTest<T, U, ComparisonMethod_Ok>
{
public:
	static bool IsEquals(T t, U u){return (t == u);}
};

template <typename T, typename U> class EqualityTest<T, U, ComparisonMethod_CastInt>
{
public:
	static bool IsEquals(T t, U u){return ((int)t == (int)u);}
};

template <typename T, typename U> class EqualityTest<T, U, ComparisonMethod_CastInt64>
{
public:
	static bool IsEquals(T t, U u){return ((_int64)t == (_int64)u);}
};

template <typename T, typename U> class EqualityTest<T, U, ComparisonMethod_UnsignedT>
{
public:
	static bool IsEquals(T t, U u)
	{
		//one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
		if(u < 0)
			return false;

		//else safe to cast to type T
		return (t == (T)u);
	}
};

template <typename T, typename U> class EqualityTest<T, U, ComparisonMethod_UnsignedU>
{
public:
	static bool IsEquals(T t, U u)
	{
		//one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
		if(t < 0)
			return false;

		//else safe to cast to type U
		return ((U)t == u);
	}
};

template <typename T, typename U, int state> class GreaterThanTest;

template <typename T, typename U> class GreaterThanTest<T, U, ComparisonMethod_Ok>
{
public:
	static bool GreaterThan(T t, U u){return (t > u);}
};

template <typename T, typename U> class GreaterThanTest<T, U, ComparisonMethod_CastInt>
{
public:
	static bool GreaterThan(T t, U u){return ((int)t > (int)u);}
};

template <typename T, typename U> class GreaterThanTest<T, U, ComparisonMethod_CastInt64>
{
public:
	static bool GreaterThan(T t, U u){return ((_int64)t > (_int64)u);}
};

template <typename T, typename U> class GreaterThanTest<T, U, ComparisonMethod_UnsignedT>
{
public:
	static bool GreaterThan(T t, U u)
	{
		//one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
		if(u < 0)
			return true;

		//else safe to cast to type T
		return (t > (T)u);
	}
};

template <typename T, typename U> class GreaterThanTest<T, U, ComparisonMethod_UnsignedU>
{
public:
	static bool GreaterThan(T t, U u)
	{
		//one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
		if(t < 0)
			return false;

		//else safe to cast to type U
		return ((U)t > u);
	}
};

//modulus is simpler than comparison, but follows much the same logic
template <typename T, typename U, int state> class ModulusHelper
{
public:
	static T Modulus(T t, U u)
	{
		if(u == 0)
			SafeIntOnDivZero();

		//trap corner case
		if(IntCompare<T,U>::isBothSigned)
		{
			if(u == -1)
				return 0;
		}

		return (T)(t % u);
	}
};

//modulus is simpler than comparison, but follows much the same logic
template <typename T, typename U> class ModulusHelper<T, U, ComparisonMethod_CastInt64>
{
public:
	static T Modulus(T t, U u)
	{
		if(u == 0)
			SafeIntOnDivZero();

		if(IntTraits<U>::isSigned && u == -1)
			return 0;

		return (T)((_int64)t % (_int64)u);
	}
};

//T is unsigned _int64, U is any signed int
template <typename T, typename U> class ModulusHelper<T, U, ComparisonMethod_UnsignedT>
{
public:
	static T Modulus(T t, U u)
	{
		if(u == 0)
			SafeIntOnDivZero();

		//u could be negative - if so, need to convert to positive
		if(u < 0)
		{
			return t % AbsValueHelper<U, GetAbsMethod<U>::method >::Abs(u);
		}

		return t % u;
	}
};

//U is unsigned _int64, T any signed int
template <typename T, typename U> class ModulusHelper<T, U, ComparisonMethod_UnsignedU>
{
public:
	static T Modulus(T t, U u)
	{
		if(u == 0)
			SafeIntOnDivZero();

		//t could be negative - if so, need to convert to positive
		if(t < 0)
		{
			return -(T)(AbsValueHelper<T, GetAbsMethod<T>::method >::Abs(t) % u);
		}

		return (T)((U)t % u);
	}
};

//core logic to determine method to check multiplication
enum MultiplicationState
{
	MultiplicationState_CastInt = 0,
	MultiplicationState_CastInt64,
	MultiplicationState_CastUint,
	MultiplicationState_CastUint64,
	MultiplicationState_Uint64Uint,
	MultiplicationState_Uint64Uint64,
	MultiplicationState_Uint64Int,
	MultiplicationState_UintUint64,
	MultiplicationState_UintInt64,
	MultiplicationState_Int64Uint,
	MultiplicationState_Int64Int,
	MultiplicationState_IntUint64,
	MultiplicationState_IntInt64,
	MultiplicationState_Error
};

template <typename T, typename U>
class MultiplicationMethod
{
public:
	enum
	{
		         //unsigned-unsigned
		method = (IntRegion<T,U>::IntZone_UintLT32_UintLT32  ? MultiplicationState_CastUint :
	             (IntRegion<T,U>::IntZone_Uint32_UintLT64 || 
				  IntRegion<T,U>::IntZone_UintLT32_Uint32)   ? MultiplicationState_CastUint64 :
				  IntCompare<T,U>::isBothUnsigned && 
				  IntTraits<T>::isUint64 && IntTraits<U>::isUint64 ? MultiplicationState_Uint64Uint64 :
				 (IntRegion<T,U>::IntZone_Uint64_Uint)       ? MultiplicationState_Uint64Uint :
				 (IntRegion<T,U>::IntZone_UintLT64_Uint64)   ? MultiplicationState_UintUint64 :
				 //unsigned-signed
				 (IntRegion<T,U>::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt :
				 (IntRegion<T,U>::IntZone_Uint32_IntLT64 ||
				  IntRegion<T,U>::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 :
				 (IntRegion<T,U>::IntZone_Uint64_Int)     ? MultiplicationState_Uint64Int :
				 (IntRegion<T,U>::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 :
				 //signed-signed
				 (IntRegion<T,U>::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt :
				 (IntRegion<T,U>::IntZone_Int32_IntLT64 ||
				  IntRegion<T,U>::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 :
				 (IntRegion<T,U>::IntZone_Int64_Int)     ? MultiplicationState_Int64Int :
				 (IntRegion<T,U>::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 :
				 //signed-unsigned
				 (IntRegion<T,U>::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt :
				 (IntRegion<T,U>::IntZone_Int32_UintLT32 ||
				  IntRegion<T,U>::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 :
				 (IntRegion<T,U>::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint :
				 (IntRegion<T,U>::IntZone_Int_Uint64)     ? MultiplicationState_IntUint64 :
				  MultiplicationState_Error)
	};
};

template <typename T, typename U, int state> class MultiplicationHelper;

template <typename T, typename U> class MultiplicationHelper<T, U, MultiplicationState_CastInt>
{
public:
	//accepts signed, both less than 32-bit
	static T Multiply(T t, U u)
	{
		int tmp = t * u;

		if(tmp > IntTraits<T>::maxInt || tmp < IntTraits<T>::minInt)
			SafeIntOnOverflow();
		
		return (T)tmp;
	}
};

template <typename T, typename U> class MultiplicationHelper<T, U, MultiplicationState_CastUint>
{
public:
	//accepts unsigned, both less than 32-bit
	static T Multiply(T t, U u)
	{
		unsigned int tmp = t * u;

		if(tmp > IntTraits<T>::maxInt)
			SafeIntOnOverflow();
		
		return (T)tmp;
	}
};

template <typename T, typename U> class MultiplicationHelper<T, U, MultiplicationState_CastInt64>
{
public:
	//mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less
	static T Multiply(T t, U u)
	{
		_int64 tmp = (_int64)t * (_int64)u;

		if(tmp > (_int64)IntTraits<T>::maxInt || tmp < (_int64)IntTraits<T>::minInt)
			SafeIntOnOverflow();
		
		return (T)tmp;
	}
};

template <typename T, typename U> class MultiplicationHelper<T, U, MultiplicationState_CastUint64>
{
public:
	//both unsigned where at least one argument is 32-bit, and both a 32-bit or less
	static T Multiply(T t, U u)
	{
		unsigned _int64 tmp = (unsigned _int64)t * (unsigned _int64)u;

		if(tmp > (unsigned _int64)IntTraits<T>::maxInt)
			SafeIntOnOverflow();
		
		return (T)tmp;
	}
};

//helper functions for 64-bit multiplication
template <typename V>
 V Int64Helper(_int64 t, _int64 u)
{
	if(u >= 0)
		return Int64Helper<V>(t, (unsigned _int64)u);

	unsigned _int64 tmp;
	//now u < 0
	if(t < 0)
	{
		//flip them both - result must be positive
		tmp = UInt64Helper<unsigned _int64>((unsigned _int64)-t, (unsigned _int64)-u);

		if(tmp > IntTraits<V>::maxInt)
			SafeIntOnOverflow();

		return (V)tmp;
	}

	//t non-negative, flip u
	tmp = UInt64Helper<unsigned _int64>((unsigned _int64)t, (unsigned _int64)-u);

	if(tmp > (unsigned _int64)IntTraits<V>::maxInt + 1)
		SafeIntOnOverflow();

	return (-(V)tmp);
}

template <typename V>
V Int64Helper(_int64 t, _int32 u)
{
	if(u >= 0)
		return Int64Helper<V>(t, (unsigned _int32)u);

	unsigned _int64 tmp;
	//now u < 0
	if(t < 0)
	{
		//flip them both - result must be positive
		tmp = UInt64Helper<unsigned _int64>((unsigned _int64)-t, (unsigned _int32)-u);

		if(tmp > IntTraits<V>::maxInt)
			SafeIntOnOverflow();

		return (V)tmp;
	}

	//t non-negative, flip u
	tmp = UInt64Helper<unsigned _int64>((unsigned _int64)t, (unsigned _int32)-u);

	if(tmp > (unsigned _int64)(IntTraits<V>::maxInt) + 1)//minInt with zero carry
		SafeIntOnOverflow();

	return -((V)tmp);
}

template <typename V>
V Int64Helper(_int64 t, unsigned _int64 u)
{
	//u is effectively 32-bit
	if((unsigned _int32)(u >> 32) == 0)
		return Int64Helper<V>(t, (unsigned _int32)u);

	//both 64-bit - most complex case
	bool neg = t < 0;
	unsigned _int64 tmp = neg ? (unsigned _int64)(-t) : t;

	if((tmp >> 32) != 0) //upper bits of both t and u are set, must overflow
		SafeIntOnOverflow();
	
	//now T is effectively < 64 bit
	tmp = UInt64Helper<unsigned _int64>(u, (unsigned _int32)tmp); 

	if(neg)
	{
		if(tmp > (unsigned _int64)IntTraits<V>::minInt)
			SafeIntOnOverflow();

		return -((V)tmp);
	}

	if(tmp > (unsigned _int64)IntTraits<V>::maxInt)
		SafeIntOnOverflow();

	return (V)tmp;
}

template <typename V>
V Int64Helper(_int32 t, unsigned _int64 u)
{
	bool neg = t < 0;
	unsigned _int32 t_tmp = neg ? (unsigned _int32)(-t) : t;

	unsigned _int64 tmp = UInt64Helper<unsigned _int64>(u, t_tmp);

	if(neg)
	{
		if(tmp > (unsigned _int64)IntTraits<V>::maxInt + 1)
			SafeIntOnOverflow();

		return -((V)tmp);
	}

	if(tmp > (unsigned _int64)IntTraits<V>::maxInt)
		SafeIntOnOverflow();

	return (V)tmp;
}

template <typename V>
 V Int64Helper(_int64 t, unsigned _int32 u)
{
	bool neg = (t < 0);

	unsigned _int64 tmp;

	if(neg)
	{
		tmp = UInt64Helper<unsigned _int64>((unsigned _int64)-t, u);

		if(tmp > (unsigned _int64)IntTraits<V>::maxInt + 1)
			SafeIntOnOverflow();

		return -((V)tmp);
	}

	tmp = UInt64Helper<unsigned _int64>(t, (unsigned _int32)u);

	if(tmp > IntTraits<V>::maxInt)
		SafeIntOnOverflow();

	return (V)tmp;
}

template <typename V>
 V UInt64Helper(unsigned _int64 t, unsigned _int64 u)
{
	// = (A * C * 2^64) + (B * C * 2^32) + (A * D * 2^32) + B * D
	//A * C must be zero, or overflow
	if(u >> 32 == 0)
	{
		return UInt64Helper<V>(t, (unsigned _int32)u);
	}
	else if((t >> 32) == 0)
	{
		return UInt64Helper<V>(u, (unsigned _int32)t);
	}
	else //(A*C) != 0
	{
		SafeIntOnOverflow();
	}
}

template <typename V>
 V UInt64Helper(unsigned _int64 t, unsigned _int32 u)
{
	//t * u are held in registers ABCD as
	//(AB) * (CD)
	//which is really
	// (A*2^32 + B) * (C*2^32 + D)
	// = (A * C * 2^64) + (B * C * 2^32) + (A * D * 2^32) + B * D
	//C = 0
	// = (A * D * 2^32) + B * D
	//thus if A*D sets any high bits, overflow
	//you then have to check the addition
	unsigned _int32 a, b, d;

	a = (unsigned _int32)(t >> 32);
	b = (unsigned _int32)t;
	d = u;

	unsigned _int64 ad = (unsigned _int64)a * d;

	if(sizeof(V) == 8)
	{
		if((unsigned _int32)(ad >> 32) != 0)
		{
			SafeIntOnOverflow();
		}

		unsigned _int64 tmp;
		unsigned _int64 bd = (unsigned _int64)b * d;

		tmp = (ad << 32) + bd;

		if(tmp < bd)
			SafeIntOnOverflow();

		return (V)tmp;
	}
	else //ad has to be zero
	{
		if(ad != 0)
			SafeIntOnOverflow();

		unsigned _int64 bd = (unsigned _int64)b * d;

		if(bd > IntTraits<V>::maxInt)
			SafeIntOnOverflow();

		return (V)bd;
	}
}

template <> class MultiplicationHelper<unsigned _int64, unsigned _int64, MultiplicationState_Uint64Uint64>
{
public:
	//U is any unsigned int up to 64-bit
	static unsigned _int64 Multiply(unsigned _int64 t, unsigned _int64 u)
	{
		return UInt64Helper<unsigned _int64>(t, u);
	}
};

template <typename U> class MultiplicationHelper<unsigned _int64, U, MultiplicationState_Uint64Uint>
{
public:
	//U is any unsigned int 64-bit or less
	static unsigned _int64 Multiply(unsigned _int64 t, U u)
	{
		return UInt64Helper<unsigned _int64>(t, (unsigned _int32)u);
	}
};

//converse of the previous function
template <typename T> class MultiplicationHelper<T, unsigned _int64, MultiplicationState_UintUint64>
{
public:
	//U is any unsigned int up to 32-bit
	static T Multiply(T t, unsigned _int64 u)
	{
		return UInt64Helper<T>(u, (unsigned _int32)t);
	}
};

template <typename U> class MultiplicationHelper<unsigned _int64, U, MultiplicationState_Uint64Int>
{
public:
	//U is any signed int, up to 64-bit
	static unsigned _int64 Multiply(unsigned _int64 t, U u)
	{
		if(u < 0)
		{
			if(t == 0)
				return 0;

			SafeIntOnOverflow();
		}

		return UInt64Helper<unsigned _int64>(t, (unsigned _int64)u);
	}
};

template <typename T> class MultiplicationHelper<T, _int64, MultiplicationState_UintInt64>
{
public:
	//T is unsigned up to 32-bit
	static T Multiply(T t, _int64 u)
	{
		if(u < 0)
		{
			if(t == 0)
				return 0;

			SafeIntOnOverflow();
		}

		return UInt64Helper<T>((unsigned _int64)u, (unsigned _int32)t);
	}
};

template <typename U> class MultiplicationHelper<_int64, U, MultiplicationState_Int64Uint>
{
public:
	//U is unsigned up to 32-bit
	static _int64 Multiply(_int64 t, U u)
	{
		return Int64Helper<_int64>(t, (unsigned _int32)u);
	}
};

template <typename U> class MultiplicationHelper<_int64, U, MultiplicationState_Int64Int>
{
public:
	//U is signed up to 64-bit
	static _int64 Multiply(_int64 t, U u)
	{
		return Int64Helper<_int64>(t, u);
	}
};

template <typename T> class MultiplicationHelper<T, unsigned _int64, MultiplicationState_IntUint64>
{
public:
	//T is signed up to 64-bit
	static T Multiply(T t, unsigned _int64 u)
	{
		return Int64Helper<T>(t, u);
	}
};

template <typename T> class MultiplicationHelper<T, _int64, MultiplicationState_IntInt64>
{
public:
	//T is signed, up to 32-bit
	static T Multiply(T t, _int64 u)
	{
		return Int64Helper<T>(u, (_int32)t);
	}
};

enum DivisionState
{
	DivisionState_OK,
	DivisionState_UnsignedSigned,
	DivisionState_SignedUnsigned32,
	DivisionState_SignedUnsigned64,
	DivisionState_SignedUnsigned,
	DivisionState_SignedSigned
};

template <typename T, typename U> class DivisionMethod
{
public:
	enum
	{
		method = (IntCompare<T, U>::isBothUnsigned ? DivisionState_OK :
	             (!IntTraits<T>::isSigned && IntTraits<U>::isSigned) ? DivisionState_UnsignedSigned :
				 (IntTraits<T>::isSigned && IntTraits<U>::isUint32 && IntTraits<T>::isLT64Bit) ? DivisionState_SignedUnsigned32 :
				 (IntTraits<T>::isSigned && IntTraits<U>::isUint64) ? DivisionState_SignedUnsigned64 :
	             (IntTraits<T>::isSigned && !IntTraits<U>::isSigned) ? DivisionState_SignedUnsigned :
				 DivisionState_SignedSigned)
	};
};

template <typename T, typename U, int state> class DivisionHelper;

template <typename T, typename U> class DivisionHelper<T, U, DivisionState_OK>
{
public:
	static T Divide(T t, U u)
	{
		if(u == 0)
			SafeIntOnDivZero();

		return (T)(t/u);
	}
};

template <typename T, typename U> class DivisionHelper<T, U, DivisionState_UnsignedSigned>
{
public:
	static T Divide(T t, U u)
	{
		if(u <= 0)
		{
			//it is always an error to try and divide an unsigned number by a negative signed number
			//unless u is bigger than t
			if(u < 0)
			{
				if(AbsValueHelper<U, GetAbsMethod<U>::method >::Abs(u) > t)
					return 0;

				SafeIntOnOverflow();
			}
			else
			{
				SafeIntOnDivZero();
			}
		}

		return (T)(t/u);
	}
};

template <typename T, typename U> class DivisionHelper<T, U, DivisionState_SignedUnsigned32>
{
public:
	static T Divide(T t, U u)
	{
		if(u == 0)
		{
			SafeIntOnDivZero();
		}

		//must explicitly upcast, or negative values of t will cause errors
		//TODO - consider adding conditional for t < 0, branch
		//upcast to unsigned long is OK if t > 0
		return (T)((_int64)t/(_int64)u);
	}
};

template <typename T> class DivisionHelper<T, unsigned _int64, DivisionState_SignedUnsigned64>
{
public:
	static T Divide(T t, unsigned _int64 u)
	{
		if(u == 0)
		{
			SafeIntOnDivZero();
		}

		if(u > (unsigned _int64)IntTraits<T>::maxInt)
		{
			//corner case
			if(t == IntTraits<T>::minInt && u == (unsigned _int64)IntTraits<T>::minInt)
			{
				//min int divided by it's own magnitude is -1
				return -1;
			}

			return 0;
		}

		//else u can safely be cast to _int64
		//TODO - could special case sizeof(T) < 8
		return (T)((_int64)t/(_int64)u);
	}
};

template <typename T, typename U> class DivisionHelper<T, U, DivisionState_SignedUnsigned>
{
public:
	static T Divide(T t, U u)
	{
		if(u == 0)
		{
			SafeIntOnDivZero();
		}

		return (T)(t/u);
	}
};

template <typename T, typename U> class DivisionHelper<T, U, DivisionState_SignedSigned>
{
public:
	static T Divide(T t, U u)
	{
		if(u == 0)
		{
			SafeIntOnDivZero();
		}

		//must test for corner case
		if(t == IntTraits<T>::minInt && u == -1)
			SafeIntOnOverflow();

		return (T)(t/u);
	}
};

enum AdditionState
{
	AdditionState_CastIntCheckMax,
	AdditionState_CastUintCheckOverflow,
	AdditionState_CastUintCheckOverflowMax,
	AdditionState_CastUint64CheckOverflow,
	AdditionState_CastUint64CheckOverflowMax,
	AdditionState_CastIntCheckMinMax,
	AdditionState_CastInt64CheckMinMax,
	AdditionState_CastInt64CheckMax,
	AdditionState_CastUint64CheckMinMax,
	AdditionState_CastUint64CheckMinMax2,
	AdditionState_CastInt64CheckOverflow,
	AdditionState_CastInt64CheckOverflowMinMax,
	AdditionState_CastInt64CheckOverflowMax,
	AdditionState_ManualCheck,
	AdditionState_Error
};

template<typename T, typename U>
class AdditionMethod
{
public:
	enum
	{
		         //unsigned-unsigned
		method = (IntRegion<T,U>::IntZone_UintLT32_UintLT32  ? AdditionState_CastIntCheckMax :
	             (IntRegion<T,U>::IntZone_Uint32_UintLT64)   ? AdditionState_CastUintCheckOverflow :
				 (IntRegion<T,U>::IntZone_UintLT32_Uint32)   ? AdditionState_CastUintCheckOverflowMax :
				 (IntRegion<T,U>::IntZone_Uint64_Uint)       ? AdditionState_CastUint64CheckOverflow :
				 (IntRegion<T,U>::IntZone_UintLT64_Uint64)   ? AdditionState_CastUint64CheckOverflowMax :
				 //unsigned-signed
				 (IntRegion<T,U>::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckMinMax :
				 (IntRegion<T,U>::IntZone_Uint32_IntLT64 ||
				  IntRegion<T,U>::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckMinMax :
				 (IntRegion<T,U>::IntZone_Uint64_Int)     ? AdditionState_CastUint64CheckMinMax :
				 (IntRegion<T,U>::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckMinMax2 :
				 //signed-signed
				 (IntRegion<T,U>::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckMinMax :
				 (IntRegion<T,U>::IntZone_Int32_IntLT64 ||
				  IntRegion<T,U>::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckMinMax :
				 (IntRegion<T,U>::IntZone_Int64_Int)     ? AdditionState_CastInt64CheckOverflow :
				 (IntRegion<T,U>::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowMinMax :
				 //signed-unsigned
				 (IntRegion<T,U>::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax :
				 (IntRegion<T,U>::IntZone_Int32_UintLT32 ||
				  IntRegion<T,U>::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax :
				 (IntRegion<T,U>::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax :
				 (IntRegion<T,U>::IntZone_Int_Uint64)     ? AdditionState_ManualCheck :
				  AdditionState_Error)
	};
};

template <typename T, typename U, int method> class AdditionHelper;

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastIntCheckMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//16-bit or less unsigned addition
		_int32 tmp = lhs + rhs;

		if(tmp > (_int32)IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastUintCheckOverflow>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//32-bit or less - both are unsigned
		unsigned _int32 tmp = (unsigned _int32)lhs + (unsigned _int32)rhs;

		//we added and it became smaller
		if(tmp < lhs)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastUintCheckOverflowMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//32-bit or less - both are unsigned
		unsigned _int32 tmp = (unsigned _int32)lhs + (unsigned _int32)rhs;

		//we added and it became smaller or we exceeded maxInt
		if(tmp < lhs || tmp > IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastUint64CheckOverflow>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//lhs unsigned _int64, rhs unsigned
		unsigned _int64 tmp = (unsigned _int64)lhs + (unsigned _int64)rhs;

		//we added and it became smaller
		if(tmp < lhs)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastUint64CheckOverflowMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//lhs unsigned _int64, rhs unsigned
		unsigned _int64 tmp = (unsigned _int64)lhs + (unsigned _int64)rhs;

		//we added and it became smaller
		if(tmp < lhs || tmp > IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastIntCheckMinMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//16-bit or less - one or both are signed
		_int32 tmp = lhs + rhs;

		if(tmp > (_int32)IntTraits<T>::maxInt || tmp < (_int32)IntTraits<T>::minInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastInt64CheckMinMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//32-bit or less - one or both are signed
		_int64 tmp = (_int64)lhs + (_int64)rhs;

		if(tmp > IntTraits<T>::maxInt || tmp < IntTraits<T>::minInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastInt64CheckMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//32-bit or less - lhs signed, rhs unsigned
		_int64 tmp = (_int64)lhs + (_int64)rhs;

		if(tmp > IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastUint64CheckMinMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//lhs is unsigned _int64, rhs signed
		if(rhs < 0)
		{
			unsigned _int64 tmp = AbsValueHelper<U, GetAbsMethod<U>::method >::Abs(rhs);

			if(tmp > lhs)
				SafeIntOnOverflow();

			return lhs - tmp;
		}

		//now we know that rhs can be safely cast into an unsigned _int64
		unsigned _int64 tmp = (unsigned _int64)lhs + (unsigned _int64)rhs;

		//we added and it became smaller
		if(tmp < lhs)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastUint64CheckMinMax2>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//lhs is unsigned and < 64-bit, rhs signed _int64
		if(rhs < 0)
		{
			if(lhs < (unsigned _int64)(-rhs))//negation is safe, since rhs is 64-bit
				SafeIntOnOverflow();

			return T(lhs + rhs);
		}

		//now we know that rhs can be safely cast into an unsigned _int64
		unsigned _int64 tmp = (unsigned _int64)lhs + (unsigned _int64)rhs;

		//special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff
		//it is not possible for the operation above to overflow, so just check max
		if(tmp > IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastInt64CheckOverflow>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//lhs is signed _int64, rhs signed
		_int64 tmp = (_int64)lhs + (_int64)rhs;

		if(lhs >= 0)
		{
			//mixed sign cannot overflow
			if(rhs >= 0 && tmp < lhs)
				SafeIntOnOverflow();
		}
		//lhs negative
		if(rhs < 0 && tmp > lhs)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastInt64CheckOverflowMinMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//rhs is signed _int64, lhs signed
		_int64 tmp = AdditionHelper<_int64, _int64, AdditionState_CastInt64CheckOverflow>::Addition((_int64)lhs, (_int64)rhs);

		//additional checks for range
		if(tmp > IntTraits<T>::maxInt || tmp < IntTraits<T>::minInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_CastInt64CheckOverflowMax>
{
public:
	static T Addition(T lhs, U rhs)
	{
		//lhs is signed _int64, rhs unsigned < 64-bit
		_int64 tmp = lhs + (_int64)rhs;

		if(tmp < lhs)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class AdditionHelper <T, U, AdditionState_ManualCheck>
{
public:
	static T Addition(T lhs, U rhs)
	{
		unsigned _int64 tmp;
		//rhs is unsigned _int64, lhs signed
		if(lhs >= 0)
		{
			tmp = lhs + rhs;

			if(tmp < (unsigned _int64)lhs || tmp > (unsigned _int64)IntTraits<T>::maxInt)
				SafeIntOnOverflow();

			return (T)tmp;
		}
		//else lhs negative - have to check range
		if(rhs > (unsigned _int64)IntTraits<T>::maxInt + AbsValueHelper<T, GetAbsMethod<T>::method >::Abs(lhs))
			SafeIntOnOverflow();

		//the result must be legal - upcast T to larger value
		if(IntTraits<T>::isLT32Bit)
			return (T)((_int32)lhs + (_int32)rhs);

		if(IntTraits<T>::is32Bit)
			return (T)((_int64)lhs + (_int64)rhs);
			
		//else T is _int64, U is unsigned _int64
		return (T)((unsigned _int64)rhs - (unsigned _int64)(-lhs));
	}
};

enum SubtractionState
{
	SubtractionState_BothUnsigned,
	SubtractionState_CastIntCheckMinMax,
	SubtractionState_CastIntCheckMin,
	SubtractionState_CastInt64CheckMinMax,
	SubtractionState_CastInt64CheckMin,
	SubtractionState_Uint64Int,
	SubtractionState_UintInt64, 
	SubtractionState_Int64Int,
	SubtractionState_IntInt64,
	SubtractionState_Int64Uint,
	SubtractionState_IntUint64,
	//states for SubtractionMethod2
	SubtractionState_CastIntCheckMinMax2,
	SubtractionState_CastInt64CheckMinMax2,
	SubtractionState_Uint64Int2,
	SubtractionState_UintInt642,
	SubtractionState_Int64Int2,
	SubtractionState_IntInt642,
	SubtractionState_Int64Uint2,
	SubtractionState_IntUint642,
	SubtractionState_Error
};

template <typename T, typename U> class SubtractionMethod
{
public:
	enum
	{
		         //unsigned-unsigned
		method = ((IntRegion<T,U>::IntZone_UintLT32_UintLT32 ||
	             (IntRegion<T,U>::IntZone_Uint32_UintLT64)   || 
				 (IntRegion<T,U>::IntZone_UintLT32_Uint32)   || 
				 (IntRegion<T,U>::IntZone_Uint64_Uint)       || 
				 (IntRegion<T,U>::IntZone_UintLT64_Uint64))  ?  SubtractionState_BothUnsigned :
				 //unsigned-signed
				 (IntRegion<T,U>::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax :
				 (IntRegion<T,U>::IntZone_Uint32_IntLT64 ||
				  IntRegion<T,U>::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax :
				 (IntRegion<T,U>::IntZone_Uint64_Int)     ? SubtractionState_Uint64Int :
				 (IntRegion<T,U>::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 :
				 //signed-signed
				 (IntRegion<T,U>::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax :
				 (IntRegion<T,U>::IntZone_Int32_IntLT64 ||
				  IntRegion<T,U>::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax :
				 (IntRegion<T,U>::IntZone_Int64_Int)     ? SubtractionState_Int64Int :
				 (IntRegion<T,U>::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 :
				 //signed-unsigned
				 (IntRegion<T,U>::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin :
				 (IntRegion<T,U>::IntZone_Int32_UintLT32 ||
				  IntRegion<T,U>::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin :
				 (IntRegion<T,U>::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint :
				 (IntRegion<T,U>::IntZone_Int_Uint64)     ? SubtractionState_IntUint64 :
				  SubtractionState_Error)
	};
};

//this is for the case of U - SafeInt<T>
template <typename T, typename U> class SubtractionMethod2
{
public:
	enum
	{
		         //unsigned-unsigned
		method = ((IntRegion<T,U>::IntZone_UintLT32_UintLT32 ||
	             (IntRegion<T,U>::IntZone_Uint32_UintLT64)   || 
				 (IntRegion<T,U>::IntZone_UintLT32_Uint32)   || 
				 (IntRegion<T,U>::IntZone_Uint64_Uint)       || 
				 (IntRegion<T,U>::IntZone_UintLT64_Uint64))  ?  SubtractionState_BothUnsigned :
				 //unsigned-signed
				 (IntRegion<T,U>::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 :
				 (IntRegion<T,U>::IntZone_Uint32_IntLT64 ||
				  IntRegion<T,U>::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 :
				 (IntRegion<T,U>::IntZone_Uint64_Int)     ? SubtractionState_Uint64Int2 :
				 (IntRegion<T,U>::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 :
				 //signed-signed
				 (IntRegion<T,U>::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckMinMax2 :
				 (IntRegion<T,U>::IntZone_Int32_IntLT64 ||
				  IntRegion<T,U>::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckMinMax2 :
				 (IntRegion<T,U>::IntZone_Int64_Int)     ? SubtractionState_Int64Int2 :
				 (IntRegion<T,U>::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 :
				 //signed-unsigned
				 (IntRegion<T,U>::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMinMax2 :
				 (IntRegion<T,U>::IntZone_Int32_UintLT32 ||
				  IntRegion<T,U>::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMinMax2 :
				 (IntRegion<T,U>::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 :
				 (IntRegion<T,U>::IntZone_Int_Uint64)     ? SubtractionState_IntUint642 :
				  SubtractionState_Error)
	};
};

template <typename T, typename U, int method> class SubtractionHelper;

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_BothUnsigned>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//both are unsigned - easy case
		if(rhs > lhs)
			SafeIntOnOverflow();

		return (T)(lhs - rhs);
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_CastIntCheckMinMax>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//both values are 16-bit or less
		//rhs is signed, so could end up increasing or decreasing
		_int32 tmp = lhs - rhs;

		if(tmp < (_int32)IntTraits<T>::minInt || tmp > (_int32)IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_CastIntCheckMinMax2>
{
public:
	static T Subtract(U lhs, T rhs)
	{
		//both values are 16-bit or less
		//rhs is signed, so could end up increasing or decreasing
		_int32 tmp = lhs - rhs;

		if(tmp < (_int32)IntTraits<T>::minInt || tmp > (_int32)IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_CastIntCheckMin>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//both values are 16-bit or less
		//rhs is unsigned - check only minimum
		_int32 tmp = lhs - rhs;

		if(tmp < (_int32)IntTraits<T>::minInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_CastInt64CheckMinMax>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//both values are 32-bit or less
		//rhs is signed, so could end up increasing or decreasing
		_int64 tmp = (_int64)lhs - (_int64)rhs;

		if(tmp < (_int64)IntTraits<T>::minInt || tmp > (_int64)IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_CastInt64CheckMinMax2>
{
public:
	static T Subtract(U lhs, T rhs)
	{
		//both values are 32-bit or less
		//rhs is signed, so could end up increasing or decreasing
		_int64 tmp = (_int64)lhs - (_int64)rhs;

		if(tmp < (_int64)IntTraits<T>::minInt || tmp > (_int64)IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_CastInt64CheckMin>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//both values are 32-bit or less
		//rhs is unsigned - check only minimum
		_int64 tmp = (_int64)lhs - (_int64)rhs;

		if(tmp < (_int64)IntTraits<T>::minInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_Uint64Int>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//lhs is an unsigned _int64, rhs signed
		//must first see if rhs is positive or negative
		if(rhs >= 0)
		{
			if((unsigned _int64)rhs > lhs)
				SafeIntOnOverflow();

			return (T)(lhs - (unsigned _int64)rhs);
		}

		//we're now effectively adding
		unsigned _int64 tmp = lhs + AbsValueHelper<U, GetAbsMethod<U>::method>::Abs(rhs);

		if(tmp < lhs)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_Uint64Int2>
{
public:
	static T Subtract(U lhs, T rhs)
	{
		if(rhs < 0)
		{
			unsigned _int64 tmp;

			tmp = lhs + (unsigned _int64)AbsValueHelper<T, GetAbsMethod<T>::method>::Abs(rhs);

			if(tmp < lhs || tmp > IntTraits<T>::maxInt)
				SafeIntOnOverflow();

			return (T)tmp;
		}

		//now both are positive
		//implies that comparison always works
		if((unsigned _int64)rhs > lhs)
		{
			//result is negative
			//implies that lhs must fit into T, and result cannot overflow
			return (T)lhs - (T)rhs;
		}
		else
		{
			//result is positive
			unsigned _int64 tmp = (unsigned _int64)lhs - (unsigned _int64)rhs;

			if(tmp > IntTraits<T>::maxInt)
				SafeIntOnOverflow();

			return (T)tmp;
		}
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_UintInt64>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//lhs is an unsigned int32 or smaller, rhs signed _int64
		//must first see if rhs is positive or negative
		if(rhs >= 0)
		{
			if((unsigned _int64)rhs > lhs)
				SafeIntOnOverflow();

			return (T)(lhs - (T)rhs);
		}

		//we're now effectively adding
		//since lhs is 32-bit, and rhs cannot exceed 2^63
		//this addition cannot overflow
		unsigned _int64 tmp = lhs + (unsigned _int64)(-rhs);//negation safe

		//but we could exceed MaxInt
		if(tmp > IntTraits<T>::maxInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_UintInt642>
{
public:
	static T Subtract(U lhs, T rhs)
	{
		//U unsigned 32-bit or less, T _int64
		if(rhs < 0)
		{
			_int64 tmp = (_int64)lhs + (-(T)rhs);

			if(tmp < lhs || tmp > IntTraits<T>::maxInt)
				SafeIntOnOverflow();

			return (T)tmp;
		}
		//else overflow not possible
		return (T)((_int64)lhs - rhs);
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_Int64Int>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//lhs is an _int64, rhs signed
		//we have essentially 4 cases:
		//
		//lhs positive, rhs positive - overflow not possible
		//lhs positive, rhs negative - equivalent to addition - result >= lhs or error
		//lhs negative, rhs positive - check result <= lhs
		//lhs negative, rhs negative - overflow not possible

		_int64 tmp = lhs - rhs;

		if(lhs >= 0 && rhs < 0)
		{
			if(tmp < lhs)
				SafeIntOnOverflow();
		}

		if(lhs < 0 && rhs >= 0)
		{
			if(tmp > lhs)
				SafeIntOnOverflow();
		}

		return (T)tmp;
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_Int64Int2>
{
public:
	static T Subtract(U lhs, T rhs)
	{
		//lhs _int64, rhs any signed int
		_int64 tmp = lhs - (_int64)(T)rhs;

		if(lhs >= 0)
		{
			//if both positive, overflow to negative not possible
			if(IntTraits<T>::isLT64Bit && tmp > IntTraits<T>::maxInt)
				SafeIntOnOverflow();

			if((T)rhs < 0)
			{
				//rhs negative, effictively addition
				if(tmp < lhs)
					SafeIntOnOverflow();
			}
		}
		else
		{
			//lhs negative
			if(IntTraits<T>::isLT64Bit && tmp < IntTraits<T>::minInt)
				SafeIntOnOverflow();

			if(rhs >= 0)
			{
				if(tmp > lhs)
					SafeIntOnOverflow();
			}
		}
		return (T)tmp;
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_IntInt64>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//lhs is a 32-bit int or less, rhs _int64
		//we have essentially 4 cases:
		//
		//lhs positive, rhs positive - rhs could be larger than lhs can represent
		//lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int
		//lhs negative, rhs positive - check tmp <= lhs and tmp < min int
		//lhs negative, rhs negative - addition cannot internally overflow, check against max

		_int64 tmp = (_int64)lhs - rhs;

		if(lhs >= 0)
		{
			//first case
			if(rhs >= 0)
			{
				if(tmp < IntTraits<T>::minInt)
					SafeIntOnOverflow();
			}
			else
			{
				//second case
				if(tmp < lhs || tmp > IntTraits<T>::maxInt)
					SafeIntOnOverflow();
			}
		}

		//third case
		if(rhs >= 0)
		{
			if(tmp > lhs || tmp < IntTraits<T>::minInt)
				SafeIntOnOverflow();
		}
		else
		{
			//fourth case
			if(tmp > IntTraits<T>::maxInt)
				SafeIntOnOverflow();
		}

		return (T)tmp;
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_IntInt642>
{
public:
	static T Subtract(U lhs, T rhs)
	{
		_int64 tmp = (_int64)lhs - (T)rhs;

		if(lhs >= 0)
		{
			if(rhs < 0)
			{
				if(tmp < lhs)
					SafeIntOnOverflow();
			}
			//else OK
		}
		else
		{
			//lhs < 0
			if(rhs > 0)
			{
				if(tmp > lhs)
					SafeIntOnOverflow();
			}
		}

		return SafeInt<T>(tmp);
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_Int64Uint>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//lhs is a 64-bit int, rhs unsigned int32 or smaller

		_int64 tmp = lhs - (_int64)rhs;

		if(tmp > lhs)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_Int64Uint2>
{
public:
	//lhs is _int64, rhs is unsigned 32-bit or smaller
	static T Subtract(U lhs, T rhs)
	{
		_int64 tmp = lhs - (_int64)rhs;

		if(tmp > IntTraits<T>::maxInt || tmp < IntTraits<T>::minInt)
			SafeIntOnOverflow();

		return (T)tmp;
	}
};

template <typename T, typename U> class SubtractionHelper<T, U, SubtractionState_IntUint64>
{
public:
	static T Subtract(T lhs, U rhs)
	{
		//lhs is any signed int, rhs unsigned int64
		//check against available range

		if(lhs < 0)
		{
			if(rhs > (unsigned _int64)(IntTraits<T>::maxInt) + 1 - AbsValueHelper<T, GetAbsMethod<T>::method>::Abs(lhs))
				SafeIntOnOverflow();
		}
		else
		{
			if(rhs > (unsigned _int64)(IntTraits<T>::maxInt) + 1 + (unsigned _int64)lhs)
				SafeIntOnOverflow();
		}

		return (T)(lhs - rhs);
	}
};

template <typename U, typename T> class SubtractionHelper<U, T, SubtractionState_IntUint642>
{
public:
	static T Subtract(U lhs, T rhs)
	{
		//we run into upcasting problems on comparison - needs 2 checks
		if(lhs < 0 || (T)lhs < (T)rhs)
			SafeIntOnOverflow();

		return (T)((U)lhs - (U)rhs);
	}
};

enum BinaryState
{
	BinaryState_OK,
	BinaryState_Int8,
	BinaryState_Int16,
	BinaryState_Int32
};

template <typename T, typename U> class BinaryMethod
{
public:
	enum
	{
		method = (sizeof(T) <= sizeof(U) || 
		           IntCompare<T,U>::isBothUnsigned ||
				   !IntTraits<U>::isSigned) ? BinaryState_OK :
	             (IntTraits<U>::isInt8) ? BinaryState_Int8 :
	             (IntTraits<U>::isInt16) ? BinaryState_Int16 : BinaryState_Int32	
	};
};

template <typename T, typename U, int method> class BinaryAndHelper;

template <typename T, typename U> class BinaryAndHelper<T, U, BinaryState_OK>
{
public:
	static T And(T lhs, U rhs){return (T)(lhs & rhs);}
};

template <typename T, typename U> class BinaryAndHelper<T, U, BinaryState_Int8>
{
public:
	static T And(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs & rhs) == (lhs & (unsigned _int8)rhs));
		return (T)(lhs & (unsigned _int8)rhs);
	}
};

template <typename T, typename U> class BinaryAndHelper<T, U, BinaryState_Int16>
{
public:
	static T And(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs & rhs) == (lhs & (unsigned _int16)rhs));
		return (T)(lhs & (unsigned _int16)rhs);
	}
};

template <typename T, typename U> class BinaryAndHelper<T, U, BinaryState_Int32>
{
public:
	static T And(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs & rhs) == (lhs & (unsigned _int32)rhs));
		return (T)(lhs & (unsigned _int32)rhs);
	}
};

template <typename T, typename U, int method> class BinaryOrHelper;

template <typename T, typename U> class BinaryOrHelper<T, U, BinaryState_OK>
{
public:
	static T Or(T lhs, U rhs){return (T)(lhs | rhs);}
};

template <typename T, typename U> class BinaryOrHelper<T, U, BinaryState_Int8>
{
public:
	static T Or(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs | rhs) == (lhs | (unsigned _int8)rhs));
		return (T)(lhs | (unsigned _int8)rhs);
	}
};

template <typename T, typename U> class BinaryOrHelper<T, U, BinaryState_Int16>
{
public:
	static T Or(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs | rhs) == (lhs | (unsigned _int16)rhs));
		return (T)(lhs | (unsigned _int16)rhs);
	}
};

template <typename T, typename U> class BinaryOrHelper<T, U, BinaryState_Int32>
{
public:
	static T Or(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs | rhs) == (lhs | (unsigned _int32)rhs));
		return (T)(lhs | (unsigned _int32)rhs);
	}
};

template <typename T, typename U, int method> class BinaryXorHelper;

template <typename T, typename U> class BinaryXorHelper<T, U, BinaryState_OK>
{
public:
	static T Xor(T lhs, U rhs){return (T)(lhs ^ rhs);}
};

template <typename T, typename U> class BinaryXorHelper<T, U, BinaryState_Int8>
{
public:
	static T Xor(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs ^ rhs) == (lhs ^ (unsigned _int8)rhs));
		return (T)(lhs ^ (unsigned _int8)rhs);
	}
};

template <typename T, typename U> class BinaryXorHelper<T, U, BinaryState_Int16>
{
public:
	static T Xor(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs ^ rhs) == (lhs ^ (unsigned _int16)rhs));
		return (T)(lhs ^ (unsigned _int16)rhs);
	}
};

template <typename T, typename U> class BinaryXorHelper<T, U, BinaryState_Int32>
{
public:
	static T Xor(T lhs, U rhs)
	{
		//cast forces sign extension to be zeros
		assert((lhs ^ rhs) == (lhs ^ (unsigned _int32)rhs));
		return (T)(lhs ^ (unsigned _int32)rhs);
	}
};

template<typename T> class SafeInt
{
public:
	SafeInt() throw()
	{
		m_int = 0;
	}

	//Having a constructor for every type of int 
	//avoids having the compiler evade our checks when doing implicit casts - 
	//e.g., SafeInt<char> s = 0x7fffffff;
	SafeInt(T i) throw()
	{
		//always safe
		m_int = i;
	}

	//provide explicit boolean converter
	SafeInt(bool b) throw()
	{
		m_int = b ? 1 : 0;
	}

	template <typename U> SafeInt(SafeInt<U> u)
	{
		*this = SafeInt<T>((U)u);
	}

	template <typename U> SafeInt(U i)
	{
		//SafeCast will throw exceptions if i won't fit in type T
		m_int = SafeCast<U, T>(i);
	}

	//the destructor is intentionally commented out - seems to make a huge difference in
	//inlining characteristics. It wasn't doing anything anyway.
	//~SafeInt(){};


	//now start overloading operators
	//assignment operator
	//constructors exist for all int types and will ensure safety

	template <typename U> SafeInt<T>& operator =(U rhs)
	{
		//use constructor to test size
		//constructor is optimized to do minimal checking based
		//on whether T can contain U
		//note - do not change this 
		*this = SafeInt<T>(rhs);
		return *this;
	}

	SafeInt<T>& operator =(T rhs) throw()
	{
		m_int = rhs;
		return *this;
	}

	template <typename U> SafeInt<T>& operator =(SafeInt<U> rhs)
	{
		*this = SafeCast<U, T>((U)rhs);
		return *this;
	}

	SafeInt<T>& operator =(SafeInt<T> rhs) throw()
	{
		m_int = rhs.m_int;
		return *this;
	}

	//casting operators
	operator char() const
	{
		return SafeCast<T, char>(m_int);
	}

	operator signed char() const
	{
		return SafeCast<T, signed char>(m_int);
	}

	operator unsigned char() const
	{
		return SafeCast<T, unsigned char>(m_int);
	}

	operator _int16() const
	{
		return SafeCast<T, _int16>(m_int);
	}

	operator unsigned _int16() const
	{
		return SafeCast<T, unsigned _int16>(m_int);
	}

	operator _int32() const
	{
		return SafeCast<T, _int32>(m_int);
	}

	operator unsigned _int32() const
	{
		return SafeCast<T, unsigned _int32>(m_int);
	}

	//the compiler knows that int == _int32
	//but not that long == _int32
	operator long() const
	{
		return SafeCast<T, long>(m_int);
	}

	operator unsigned long() const
	{
		return SafeCast<T, unsigned long>(m_int);
	}

	operator _int64() const
	{
		return SafeCast<T, _int64>(m_int);
	}

	operator unsigned _int64() const
	{
		return SafeCast<T, unsigned _int64>(m_int);
	}

	//if you need a pointer to the data
	//this could be dangerous, but allows you to correctly pass
	//instances of this class to APIs that take a pointer to an integer
	//also see overloaded address-of operator below
	T* Ptr() throw() {return &m_int;}
	const T* Ptr() const throw() {return &m_int;}

	//or if SafeInt<T>::Ptr() is inconvenient, use the overload
	// operator & 
	//This allows you to do unsafe things!
	//It is meant to allow you to more easily
	//pass a SafeInt into things like ReadFile
	T* operator &() throw() {return &m_int;}
	const T* operator &() const throw() {return &m_int;}

	//unary operators
	bool operator !() const throw() {return (!m_int) ? true : false;}
	
	//operator + (unary) 
	//note - normally, the '+' and '-' operators will upcast to a signed int
	//for T < 32 bits. This class changes behavior to preserve type
	const SafeInt<T>& operator +(void) const throw() { return *this; };

	//unary  - 
		
	SafeInt<T> operator -() const
	{
		if(IntTraits<T>::isSigned)
		{
			//corner case
			if(m_int == IntTraits<T>::minInt)
				SafeIntOnOverflow();

			//cast improves perf in the case of small ints
			return SafeInt<T>((T)-m_int);
		}
		//no-op for unsigned - generates warning 4146 at warning levels 2 and above
		return SafeInt<T>((T)-m_int);
	}

	//prefix increment operator
	SafeInt<T>& operator ++()
	{
		if(m_int == IntTraits<T>::maxInt)
		{
			SafeIntOnOverflow();
		}
		++m_int;
		return *this;
	}
	
	//prefix decrement operator
	SafeInt<T>& operator --()
	{
		if(m_int == IntTraits<T>::minInt)
		{
			SafeIntOnOverflow();
		}
		--m_int;
		return *this;
	}

	//note that postfix operators have inherently worse perf
	//characteristics

	//postfix increment operator
	SafeInt<T> operator ++(int) //dummy arg to comply with spec
	{
		if(m_int == IntTraits<T>::maxInt)
		{
			SafeIntOnOverflow();
		}

		SafeInt<T> tmp = m_int;

		m_int++;
		return tmp;
	}

	//postfix decrement operator
	SafeInt<T> operator --(int) //dummy arg to comply with spec
	{
		if(m_int == IntTraits<T>::minInt)
		{
			SafeIntOnOverflow();
		}

		SafeInt<T> tmp = m_int;
		m_int--;
		return tmp;
	}

	//one's complement
	//note - this operator will normally change size to an int
	//cast in return improves perf and maintains type
	SafeInt<T> operator ~() const throw() {return SafeInt<T>((T)~m_int);}

	//binary operators
	//
	// arithmetic binary operators
	// % modulus
	// * multiplication
	// / division
	// + addition
	// - subtraction
	//
	// For each of the arithmetic operators, you will need to 
	// use them as follows:
	//
	// SafeInt<char> c = 2;
	// SafeInt<int>  i = 3;
	//
	// SafeInt<int> i2 = i op (char)c;
	// OR
	// SafeInt<char> i2 = (int)i op c;
	//
	// The base problem is that if the lhs and rhs inputs are different SafeInt types
	// it is not possible in this implementation to determine what type of SafeInt
	// should be returned. You have to let the class know which of the two inputs
	// need to be the return type by forcing the other value to the base integer type.
	//
	// Note - as per feedback from Scott Meyers, I'm exploring how to get around this.
	//
	// The case of:
	//
	// SafeInt<T> i, j, k;
	// i = j op k;
	//
	// works just fine and no unboxing is needed because the return type is not ambiguous.

	//modulus
	//modulus has some convenient properties - 
	//first, the magnitude of the return can never be
	//larger than the lhs operand, and it must be the same sign
	//as well. It does, however, suffer from the same promotion
	//problems as comparisons, division and other operations
	template <typename U>
	SafeInt<T> operator %(U rhs) const
	{
		return SafeInt<T>(ModulusHelper<T, U, ValidComparison<T, U>::method>::Modulus(m_int, rhs));
	}

	SafeInt<T> operator %(SafeInt<T> rhs) const
	{
		return SafeInt<T>(ModulusHelper<T, T, ValidComparison<T, T>::method>::Modulus(m_int, rhs));
	}

	//modulus assignment
	template <typename U>
	SafeInt<T>& operator %=(U rhs)
	{
		m_int = ModulusHelper<T, U, ValidComparison<T, U>::method>::Modulus(m_int, rhs);
		return *this;
	}

	template <typename U>
	SafeInt<T>& operator %=(SafeInt<U> rhs)
	{
		m_int = ModulusHelper<T, U, ValidComparison<T, U>::method>::Modulus(m_int, (U)rhs);
		return *this;
	}

	//multiplication
	template <typename U>
	SafeInt<T> operator *(U rhs) const
	{
		return SafeInt<T>(MultiplicationHelper<T, U, MultiplicationMethod<T, U>::method>::Multiply(m_int, rhs));
	}

	SafeInt<T> operator *(SafeInt<T> rhs) const
	{
		return SafeInt<T>(MultiplicationHelper<T, T, MultiplicationMethod<T, T>::method>::Multiply(m_int, (T)rhs));
	}

	//multiplication assignment
	SafeInt<T>& operator *=(SafeInt<T> rhs)
	{
		m_int = MultiplicationHelper<T, T, MultiplicationMethod<T, T>::method>::Multiply(m_int, (T)rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator *=(U rhs)
	{
		m_int = MultiplicationHelper<T, U, MultiplicationMethod<T, U>::method>::Multiply(m_int, rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator *=(SafeInt<U> rhs)
	{
		m_int = MultiplicationHelper<T, U, MultiplicationMethod<T, U>::method>::Multiply(m_int, (U)rhs);
		return *this;
	}

	//division
	template <typename U>
	SafeInt<T> operator /(U rhs) const
	{
		return DivisionHelper<T, U, DivisionMethod<T, U>::method>::Divide(m_int, rhs);			
	}

	SafeInt<T> operator /(SafeInt<T> rhs) const
	{
		return SafeInt<T>(DivisionHelper<T, T, DivisionMethod<T, T>::method>::Divide(m_int, (T)rhs));			
	}

	//division assignment
	SafeInt<T>& operator /=(SafeInt<T> i)
	{
		m_int = DivisionHelper<T, T, DivisionMethod<T, T>::method>::Divide(m_int, (T)i);
		return *this;
	}

	template <typename U> SafeInt<T>& operator /=(U i)
	{
		m_int = DivisionHelper<T, U, DivisionMethod<T, U>::method>::Divide(m_int, i);
		return *this;
	}

	template <typename U> SafeInt<T>& operator /=(SafeInt<U> i)
	{
		m_int = DivisionHelper<T, U, DivisionMethod<T, U>::method>::Divide(m_int, (U)i);
		return *this;
	}

	//for addition and subtraction

	//addition
	SafeInt<T> operator +(SafeInt<T> rhs) const
	{
		return SafeInt<T>(AdditionHelper<T, T, AdditionMethod<T,T>::method>::Addition(m_int, (T)rhs));
	}

	template <typename U>
	SafeInt<T> operator +(U rhs) const
	{
		return SafeInt<T>(AdditionHelper<T, U, AdditionMethod<T,U>::method>::Addition(m_int, rhs));
	}

	//addition assignment
	SafeInt<T>& operator +=(SafeInt<T> rhs)
	{
		m_int = AdditionHelper<T, T, AdditionMethod<T,T>::method>::Addition(m_int, (T)rhs);
		return *this;
	}

	template <typename U>
	SafeInt<T>& operator +=(U rhs)
	{
		m_int = AdditionHelper<T, U, AdditionMethod<T,U>::method>::Addition(m_int, rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator +=(SafeInt<U> rhs)
	{
		m_int = AdditionHelper<T, U, AdditionMethod<T,U>::method>::Addition(m_int, (U)rhs);
		return *this;
	}

	//subtraction
	template <typename U>
	SafeInt<T> operator -(U rhs) const
	{
		return SafeInt<T>(SubtractionHelper<T, U, SubtractionMethod<T,U>::method>::Subtract(m_int, rhs));
	}

	SafeInt<T> operator -(SafeInt<T> rhs) const
	{
		return SafeInt<T>(SubtractionHelper<T, T, SubtractionMethod<T,T>::method>::Subtract(m_int, (T)rhs));
	}

	//subtraction assignment
	SafeInt<T>& operator -=(SafeInt<T> rhs)
	{
		m_int = SubtractionHelper<T, T, SubtractionMethod<T,T>::method>::Subtract(m_int, (T)rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator -=(U rhs)
	{
		m_int = SubtractionHelper<T, U, SubtractionMethod<T,U>::method>::Subtract(m_int, rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator -=(SafeInt<U> rhs)
	{
		m_int = SubtractionHelper<T, U, SubtractionMethod<T,U>::method>::Subtract(m_int, (U)rhs);
		return *this;
	}

	//comparison operators
	//additional overloads defined outside the class at the bottom of
	//the header to allow for cases where the SafeInt is the rhs value

	// less than
	template <typename U>
	bool operator <(U rhs) const throw()
	{
		return GreaterThanTest<U, T, ValidComparison<U, T>::method>::GreaterThan(rhs, m_int);
	}

	bool operator <(SafeInt<T> rhs) const throw()
	{
		return m_int < (T)rhs;
	}

	//greater than or eq.
	template <typename U>
	bool operator >=(U rhs) const throw() 
	{
		return !GreaterThanTest<U, T, ValidComparison<U, T>::method>::GreaterThan(rhs, m_int);
	}

	bool operator >=(SafeInt<T> rhs) const throw()
	{
		return m_int >= (T)rhs;
	}

	// greater than
	template <typename U>
	bool operator >(U rhs) const throw()
	{
		return GreaterThanTest<T, U, ValidComparison<T, U>::method>::GreaterThan(m_int, rhs);
	}

	bool operator >(SafeInt<T> rhs) const throw()
	{
		return m_int > (T)rhs;
	}

	//less than or eq.
	template <typename U>
	bool operator <=(U rhs) const throw() 
	{
		return !GreaterThanTest<T, U, ValidComparison<T, U>::method>::GreaterThan(m_int, rhs);
	}

	//same type - easy path
	bool operator <=(SafeInt<T> rhs) const throw()
	{
		return m_int <= (T)rhs;
	}

	//equality
	template <typename U>
	bool operator ==(U rhs) const throw() 
	{
		return EqualityTest<T, U, ValidComparison<T, U>::method>::IsEquals(m_int, rhs);
	}

	//need an explicit override for type bool
	bool operator ==(bool rhs) const throw()
	{
		return (m_int == 0 ? false : true) == rhs;
	}

	bool operator ==(SafeInt<T> rhs) const throw() {return m_int == (T)rhs;}

	//!= operators
	template <typename U>
	bool operator !=(U rhs) const throw() 
	{
		return !EqualityTest<T, U, ValidComparison<T, U>::method>::IsEquals(m_int, rhs);
	}

	bool operator !=(bool b) const
	{
		return (m_int == 0 ? false : true) != b;
	}

	bool operator !=(SafeInt<T> rhs) const throw() {return m_int != (T)rhs;}

	//shift operators
	//Note - shift operators ALWAYS return the same type as the lhs
	//specific version for SafeInt<T> not needed - 
	//code path is exactly the same as for SafeInt<U> as rhs

	//left shift
	//Also, shifting > bitcount is undefined - trap in debug
	template <typename U> 
	SafeInt<T> operator <<(U bits) const throw()
	{
		if(IntTraits<U>::isSigned)
            assert(bits >= 0);

		assert(bits < IntTraits<T>::bitCount);

		return SafeInt<T>((T)(m_int << bits));
	}

	template <typename U> 
	SafeInt<T> operator <<(SafeInt<U> bits) const throw()
	{
		if(IntTraits<U>::isSigned)
            assert(bits >= 0);

		assert(bits < IntTraits<T>::bitCount);

		return SafeInt<T>((T)(m_int << (U)bits));
	}

	//left shift assignment

	template <typename U>
	SafeInt<T>& operator <<=(U bits) throw()
	{
		if(IntTraits<U>::isSigned)
			assert(bits >= 0);

		assert(bits < IntTraits<T>::bitCount);

		m_int <<= bits;
		return *this;
	}

	template <typename U>
	SafeInt<T>& operator <<=(SafeInt<U> bits) throw()
	{
		if(IntTraits<U>::isSigned)
			assert((U)bits >= 0);

		assert((U)bits < IntTraits<T>::bitCount);

		m_int <<= (U)bits;
		return *this;
	}

	//right shift
	template <typename U> 
	SafeInt<T> operator >>(U bits) const throw()
	{
		if(IntTraits<U>::isSigned)
            assert(bits >= 0);

		assert(bits < IntTraits<T>::bitCount);

		return SafeInt<T>((T)(m_int >> bits));
	}

	template <typename U> 
	SafeInt<T> operator >>(SafeInt<U> bits) const throw()
	{
		if(IntTraits<U>::isSigned)
            assert(bits >= 0);

		assert(bits < IntTraits<T>::bitCount);

		return SafeInt<T>((T)(m_int >> (U)bits));
	}

	//right shift assignment
	template <typename U>
	SafeInt<T>& operator >>=(U bits) throw()
	{
		if(IntTraits<U>::isSigned)
			assert(bits >= 0);

		assert(bits < IntTraits<T>::bitCount);

		m_int >>= bits;
		return *this;
	}

	template <typename U>
	SafeInt<T>& operator >>=(SafeInt<U> bits) throw()
	{
		if(IntTraits<U>::isSigned)
			assert((U)bits >= 0);

		assert((U)bits < IntTraits<T>::bitCount);

		m_int >>= (U)bits;
		return *this;
	}

	//bitwise operators
	//this only makes sense if we're dealing with the same type and size
	//demand a type T, or something that fits into a type T

	//bitwise &
	SafeInt<T> operator &(SafeInt<T> rhs) const throw()
	{
		return SafeInt<T>(m_int & (T)rhs);
	}

	template <typename U>
	SafeInt<T> operator &(U rhs) const throw()
	{
		//we want to avoid setting bits by surprise
		//consider the case of lhs = int, value = 0xffffffff
		//                     rhs = char, value = 0xff
		//
		//programmer intent is to get only the lower 8 bits
		//normal behavior is to upcast both sides to an int
		//which then sign extends rhs, setting all the bits

		//If you land in the assert, this is because the bitwise operator
		//was causing unexpected behavior. Fix is to properly cast your inputs
		//so that it works like you meant, not unexpectedly

		return SafeInt<T>(BinaryAndHelper<T, U, BinaryMethod<T,U>::method>::And(m_int, rhs));
	}

	//bitwise & assignment
	SafeInt<T>& operator &=(SafeInt<T> rhs) throw()
	{
		m_int &= (T)rhs;
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator &=(U rhs) throw()
	{
		m_int = BinaryAndHelper<T, U, BinaryMethod<T,U>::method>::And(m_int, rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator &=(SafeInt<U> rhs) throw()
	{
		m_int = BinaryAndHelper<T, U, BinaryMethod<T,U>::method>::And(m_int, (U)rhs);
		return *this;
	}

	//XOR
	SafeInt<T> operator ^(SafeInt<T> rhs) const throw()
	{
		return SafeInt<T>((T)(m_int ^ (T)rhs));
	}

	template <typename U>
	SafeInt<T> operator ^(U rhs) const throw()
	{
		//If you land in the assert, this is because the bitwise operator
		//was causing unexpected behavior. Fix is to properly cast your inputs
		//so that it works like you meant, not unexpectedly

		return SafeInt<T>(BinaryXorHelper<T, U, BinaryMethod<T,U>::method>::Xor(m_int, rhs));
	}

	//XOR assignment
	SafeInt<T>& operator ^=(SafeInt<T> rhs) throw()
	{
		m_int ^= (T)rhs;
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator ^=(U rhs) throw()
	{
		m_int = BinaryXorHelper<T, U, BinaryMethod<T,U>::method>::Xor(m_int, rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator ^=(SafeInt<U> rhs) throw()
	{
		m_int = BinaryXorHelper<T, U, BinaryMethod<T,U>::method>::Xor(m_int, (U)rhs);
		return *this;
	}

	//bitwise OR
	SafeInt<T> operator |(SafeInt<T> rhs) const throw()
	{
		return SafeInt<T>((T)(m_int | (T)rhs));
	}

	template <typename U>
	SafeInt<T> operator |(U rhs) const throw()
	{
		return SafeInt<T>(BinaryOrHelper<T, U, BinaryMethod<T,U>::method>::Or(m_int, rhs));
	}

	//bitwise OR assignment
	SafeInt<T>& operator |=(SafeInt<T> rhs) throw()
	{
		m_int |= (T)rhs;
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator |=(U rhs) throw()
	{
		m_int = BinaryOrHelper<T, U, BinaryMethod<T,U>::method>::Or(m_int, rhs);
		return *this;
	}

	template <typename U> 
	SafeInt<T>& operator |=(SafeInt<U> rhs) throw()
	{
		m_int = BinaryOrHelper<T, U, BinaryMethod<T,U>::method>::Or(m_int, (U)rhs);
		return *this;
	}

	//logical operators
	//logical operators are like comparison operators
	//because the return value is the same regardless of 
	//what type is on the RHS or the LHS

	//and as it turns out, we need some overloads
	//bool constructor has a little overhead
	//possible combinations:
	// SafeInt<T>, SafeInt<T> - internal
	// SafeInt<T>, U          - internal
	// SafeInt<T>, bool       - internal
	// bool, SafeInt<T>       - external
	// U, SafeInt<T>          - external
	// SafeInt<U>, SafeInt<T> - external

	//logical OR
	bool operator ||(SafeInt<T> rhs) const throw()
	{
		return m_int || (T)rhs;
	}

	template <typename U>
	bool operator ||(U rhs) const throw()
	{
		return m_int || rhs;
	}

	bool operator ||(bool rhs) const throw()
	{
		return m_int || rhs;
	}

	//logical &&
	bool operator &&(SafeInt<T> rhs) const throw()
	{
		return m_int && (T)rhs;
	}

	template <typename U>
	bool operator &&(U rhs) const throw()
	{
		return m_int && rhs;
	}

	bool operator &&(bool rhs) const throw()
	{
		return m_int && rhs;
	}

	//miscellaneous helper functions
	SafeInt<T> Min(SafeInt<T> test, SafeInt<T> floor = SafeInt<T>(IntTraits<T>::minInt)) const throw()
	{
		T tmp = test < m_int ? test : m_int;
		return tmp < floor ? floor : tmp;
	}

	SafeInt<T> Max(SafeInt<T> test, SafeInt<T> upper = SafeInt<T>(IntTraits<T>::maxInt)) const throw()
	{
		T tmp = test > m_int ? test : m_int;
		return tmp > upper ? upper : tmp;
	}

	void Swap( SafeInt<T>& with ) throw()
	{
		T temp( m_int );
		m_int = with.m_int;
		with.m_int = temp;
	}

	static SafeInt<T> SafeAtoI(const char* input)
	{
		return SafeTtoI(input);
	}

	static SafeInt<T> SafeWtoI(const wchar_t* input)
	{
		return SafeTtoI(input);
	}

private:
	
	//this function keeps the casting operator from recursing

	template <typename U>
	static U SafeCast(const bool From)
	{
		return (U)(From ? 1 : 0);
	}

	template <typename T, typename U>
	static U SafeCast(const T From)
	{
		return SafeCastHelper<U, T, GetCastMethod<U, T>::method>::Cast(From);
	}

	//this is almost certainly not the best optimized version of atoi,
	//but it does not display a typical bug where it isn't possible to set MinInt
	//and it won't allow you to overflow your integer
	//This is here because it is useful, and it is an example of what
	//can be done easily with SafeInt
	template <typename U>
	static SafeInt<T> SafeTtoI(U* input)
	{
		U* tmp  = input;
		SafeInt<T> s;
		bool negative = false;
		
		if(input == NULL || input[0] == 0)
			SafeIntOnOverflow();

		switch(*tmp)
		{
		case '-':
			tmp++;
			negative = true;
			break;
		case '+':
			tmp++;
			break;
		}

		while(*tmp != 0)
		{
			if(*tmp < '0' || *tmp > '9')
				break;
			
			if((T)s != 0)
				s *= (T)10;

			if(!negative)
				s += (T)(*tmp - '0');
			else
                s -= (T)(*tmp - '0');

			tmp++;
		}

		return s;
	}

	T m_int;
};

//externally defined functions for the case of U op SafeInt<T>
template <typename T, typename U>
bool operator <(U lhs, SafeInt<T> rhs) throw()
{
	return GreaterThanTest<T, U, ValidComparison<T, U>::method>::GreaterThan((T)rhs, lhs);
}

template <typename T, typename U>
bool operator <(SafeInt<U> lhs, SafeInt<T> rhs) throw()
{
	return GreaterThanTest<T, U, ValidComparison<T, U>::method>::GreaterThan((T)rhs, (U)lhs);
}

//greater than
template <typename T, typename U>
bool operator >(U lhs, SafeInt<T> rhs) throw()
{
	return GreaterThanTest<U, T, ValidComparison<U, T>::method>::GreaterThan(lhs, (T)rhs);
}

template <typename T, typename U>
bool operator >(SafeInt<T> lhs, SafeInt<U> rhs) throw()
{
	return GreaterThanTest<T, U, ValidComparison<T, U>::method>::GreaterThan((T)lhs, (U)rhs);
}


//greater than or equal
template <typename T, typename U>
bool operator >=(U lhs, SafeInt<T> rhs) throw()
{
	return !GreaterThanTest<T, U, ValidComparison<T, U>::method>::GreaterThan((T)rhs, lhs);
}

template <typename T, typename U>
bool operator >=(SafeInt<T> lhs, SafeInt<U> rhs) throw()
{
	return !GreaterThanTest<U, T, ValidComparison<U, T>::method>::GreaterThan((U)rhs, (T)lhs);
}

//less than or equal
template <typename T, typename U>
bool operator <=(U lhs, SafeInt<T> rhs) throw()
{
	return !GreaterThanTest<U, T, ValidComparison<U, T>::method>::GreaterThan(lhs, (T)rhs);
}

template <typename T, typename U>
bool operator <=(SafeInt<T> lhs, SafeInt<U> rhs) throw()
{
	return !GreaterThanTest<T, U, ValidComparison<T, U>::method>::GreaterThan((T)lhs, (U)rhs);
}

//equality
//explicit overload for bool
template <typename T>
bool operator ==(bool lhs, SafeInt<T> rhs) throw()
{
	return lhs == ((T)rhs == 0 ? false : true);
}

template <typename T, typename U>
bool operator ==(U lhs, SafeInt<T> rhs) throw()
{
	return EqualityTest<T, U, ValidComparison<T, U>::method>::IsEquals(rhs, lhs);
}

template <typename T, typename U>
bool operator ==(SafeInt<T> lhs, SafeInt<U> rhs) throw()
{
	return EqualityTest<T, U, ValidComparison<T, U>::method>::IsEquals((T)lhs, (U)rhs);
}

//not equals
template <typename T, typename U>
bool operator !=(U lhs, SafeInt<T> rhs) throw()
{
	return !EqualityTest<T, U, ValidComparison<T, U>::method>::IsEquals(rhs, lhs);
}

template <typename T>
bool operator !=(bool lhs, SafeInt<T> rhs) throw()
{
	return ((T)rhs == 0 ? false : true) != lhs;
}

template <typename T, typename U>
bool operator !=(SafeInt<T> lhs, SafeInt<U> rhs) throw()
{
	return !EqualityTest<T, U, ValidComparison<T, U>::method>::IsEquals(lhs, rhs);
}

//modulus
template <typename T, typename U>
SafeInt<T> operator %(U lhs, SafeInt<T> rhs)
{
	//value of return depends on sign of lhs
	//this one may not be safe - bounds check in constructor
	//if lhs is negative and rhs is unsigned, this will throw an exception

	//fast-track the simple case
	if(sizeof(T) == sizeof(U) &&
		IntTraits<T>::isSigned == IntTraits<U>::isSigned)
	{
		if(rhs == 0)
			SafeIntOnDivZero();

		if(IntTraits<T>::isSigned && (T)rhs == -1)
			return 0;

		return SafeInt<T>((T)(lhs % (T)rhs));
	}

	return SafeInt<T>( (SafeInt<U>(lhs) % (T)rhs) );
}

//multiplication
template <typename T, typename U> 
SafeInt<T> operator *(U lhs, SafeInt<T> rhs)
{
	return MultiplicationHelper<T, U, MultiplicationMethod<T, U>::method>::Multiply((T)rhs, lhs);
}

//division
template <typename T, typename U> SafeInt<T> operator /(U lhs, SafeInt<T> rhs)
{
	//corner case - has to be handled seperately
	if(DivisionMethod<U,T>::method == DivisionState_UnsignedSigned)
	{
		if((T)rhs <= 0)
		{
			if((T)rhs == 0)
				SafeIntOnDivZero();

			if(sizeof(U) >= 4 && sizeof(T) <= sizeof(U))
			{
				//problem case - normal casting behavior changes meaning
				//flip rhs to positive
				//any operator casts now do the right thing
				U tmp;
				if(sizeof(T) == 4)
					tmp = lhs/(U)(unsigned _int32)(-(T)rhs);
				else
					tmp = lhs/(U)(-(T)rhs);

				if(tmp > IntTraits<T>::maxInt)
				{
					//corner case
#pragma warning(push)
#pragma warning(disable:4307) //TODO - pull this out like the rest of the class and get rid or warnings
					if(tmp == (U)IntTraits<T>::maxInt + 1)
						return SafeInt<T>(IntTraits<T>::minInt);
#pragma warning(pop)

					SafeIntOnOverflow();
				}

				return -SafeInt<T>((T)tmp);
			}

			return SafeInt<T>(lhs/(T)rhs);
		}

		return SafeInt<T>(lhs/(T)rhs);
	}

	if(IntCompare<T,U>::isBothSigned)
	{
		if(lhs == IntTraits<U>::minInt && (T)rhs == -1)
		{
			//corner case of a corner case - lhs = min int, rhs = -1, 
			//but rhs is the return type, so in essence, we can return -lhs
			if(sizeof(U) < sizeof(T))
				return SafeInt<T>((T)(-(T)lhs));

			SafeIntOnOverflow();
		}
	}

	//otherwise normal logic works with addition of bounds check when casting from U->T
	return SafeInt<T>(DivisionHelper<U,T, DivisionMethod<U,T>::method>::Divide(lhs, (T)rhs));
}

//addition
template <typename T, typename U>
SafeInt<T> operator +(U lhs, SafeInt<T> rhs)
{
	return SafeInt<T>(AdditionHelper<T, U, AdditionMethod<T,U>::method>::Addition((T)rhs, lhs));
}

//subtraction
template <typename T, typename U>
SafeInt<T> operator -(U lhs, SafeInt<T> rhs)
{
	return SafeInt<T>(SubtractionHelper<U, T, SubtractionMethod2<U,T>::method>::Subtract(lhs, (T)rhs));
}

//overrides designed to deal with cases where a SafeInt is assigned out
// to a normal int - this at least makes the last operation safe
//+=
template <typename T, typename U>
T operator +=(T lhs, SafeInt<U> rhs)
{
	return AdditionHelper<T, U, AdditionMethod<T,U>::method>::Addition(lhs, (U)rhs);
}

template <typename T, typename U>
T operator -=(T lhs, SafeInt<U> rhs)
{
	return SubtractionHelper<T, U, SubtractionMethod<T,U>::method>::Subtract(lhs, (U)rhs);
}

template <typename T, typename U>
T operator *=(T lhs, SafeInt<U> rhs)
{
	return MultiplicationHelper<T, U, MultiplicationMethod<T, U>::method>::Multiply(lhs, (U)rhs);
}

template <typename T, typename U>
T operator /=(T lhs, SafeInt<U> rhs)
{
	return DivisionHelper<T,U, DivisionMethod<T,U>::method>::Divide(lhs, (U)rhs);
}

template <typename T, typename U>
T operator %=(T lhs, SafeInt<U> rhs)
{
	//BUGBUGBUG
	return (T)(SafeInt<T>(lhs) % (U)rhs);
}

template <typename T, typename U>
T operator &=(T lhs, SafeInt<U> rhs) throw()
{
	return BinaryAndHelper<T, U, BinaryMethod<T,U>::method>::And(lhs, (U)rhs);
}

template <typename T, typename U>
T operator ^=(T lhs, SafeInt<U> rhs) throw()
{
	return BinaryXorHelper<T, U, BinaryMethod<T,U>::method>::Xor(lhs, (U)rhs);
}

template <typename T, typename U>
T operator |=(T lhs, SafeInt<U> rhs) throw()
{
	return BinaryOrHelper<T, U, BinaryMethod<T,U>::method>::Or(lhs, (U)rhs);
}

template <typename T, typename U>
T operator <<=(T lhs, SafeInt<U> rhs) throw()
{
	return (T)(SafeInt<T>(lhs) << (U)rhs);
}

template <typename T, typename U>
T operator >>=(T lhs, SafeInt<U> rhs) throw()
{
	return (T)(SafeInt<T>(lhs) >> (U)rhs);
}

//specific pointer overrides
template <typename T, typename U>
T* operator +=(T* lhs, SafeInt<U> rhs)
{
	SafeInt<size_t> ptr_val = (size_t)lhs;
	return (T*)(size_t)(ptr_val + (ptr_diff)(SafeInt<ptr_diff>rhs * sizeof(T)));
}

template <typename T, typename U>
T* operator *=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

template <typename T, typename U>
T* operator /=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

template <typename T, typename U>
T* operator %=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

template <typename T, typename U>
T* operator &=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

template <typename T, typename U>
T* operator ^=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

template <typename T, typename U>
T* operator |=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

template <typename T, typename U>
T* operator <<=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

template <typename T, typename U>
T* operator >>=(T* lhs, SafeInt<U> rhs)
{
	//this operator explicitly not supported
	C_ASSERT(false);
	return NULL;
}

//shift operators
//NOTE - shift operators always return the type of the lhs argument

//left shift
template <typename T, typename U>
SafeInt<U> operator <<(U lhs, SafeInt<T> bits) throw()
{
	if(IntTraits<T>::isSigned)
        assert((T)bits >= 0);

	assert((T)bits < IntTraits<U>::bitCount);

	return SafeInt<U>((U)(lhs << (T)bits));
}

//right shift
template <typename T, typename U>
SafeInt<U> operator >>(U lhs, SafeInt<T> bits) throw()
{
	if(IntTraits<T>::isSigned)
        assert((T)bits >= 0);

	assert((T)bits < IntTraits<U>::bitCount);

	return SafeInt<U>((U)(lhs >> (T)bits));
}

//bitwise operators
//this only makes sense if we're dealing with the same type and size
//demand a type T, or something that fits into a type T

//bitwise &
template <typename T, typename U>
SafeInt<T> operator &(U lhs, SafeInt<T> rhs) throw()
{
	return SafeInt<T>(BinaryAndHelper<T, U, BinaryMethod<T,U>::method>::And((T)rhs, lhs));
}

//bitwise XOR
template <typename T, typename U>
SafeInt<T> operator ^(U lhs, SafeInt<T> rhs) throw()
{
	return SafeInt<T>(BinaryXorHelper<T, U, BinaryMethod<T,U>::method>::Xor((T)rhs, lhs));
}

//bitwise OR
template <typename T, typename U>
SafeInt<T> operator |(U lhs, SafeInt<T> rhs) throw()
{
	return SafeInt<T>(BinaryOrHelper<T, U, BinaryMethod<T,U>::method>::Or((T)rhs, lhs));
}

//logical operators
//logical OR
template <typename T>
bool operator ||(bool lhs, SafeInt<T> rhs) throw()
{
	return lhs || (T)rhs;
}

template <typename T, typename U>
bool operator ||(U lhs, SafeInt<T> rhs) throw()
{
	return lhs || (T)rhs;
}

template <typename T, typename U>
bool operator ||(SafeInt<U> lhs, SafeInt<T> rhs) throw()
{
	return (U)lhs || (T)rhs;
}

//logical AND
template <typename T>
bool operator &&(bool lhs, SafeInt<T> rhs) throw()
{
	return lhs && (T)rhs;
}

template <typename T, typename U>
bool operator &&(U lhs, SafeInt<T> rhs) throw()
{
	return lhs && (T)rhs;
}

template <typename T, typename U>
bool operator &&(SafeInt<U> lhs, SafeInt<T> rhs) throw() 
{
	return (U)lhs && (T)rhs;
}

#pragma warning(pop)

#endif //SAFEINT_HPP